refactor: replace ./make (python3) with ./mk (makefile) (#343)

This pull request fixes https://github.com/ooni/probe/issues/1471. We have replaced the original build script (`./make`) with the `./mk` makefile (executable using `#!/usr/bin/make -f`). We concluded supporting direct builds from Windows is not worth the effort and halving the code we need to maintain is probably a good plus. Both macOS and Linux install GNU make at `/usr/bin/make`, so we should be okay in the common use cases.

I significantly simplified the management of Go versioning by requiring the user to manage it and by enforcing that we are using the desired Go version. This speeds up builds and works in sane operating systems that use the last version of a specific package. Otherwise, it's possible to use the `go get golang.org/dl/go${version}` feature.

The remaining question mark was related to updating the Android SDK. I have determined that a good course of action is pinning to the latest CLI tools and always forcing the CLI tools to install the latest required packages (e.g., the NDK).
This commit is contained in:
Simone Basso 2021-05-11 16:15:13 +02:00 committed by GitHub
parent 6841db6cb0
commit b2209bb637
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 668 additions and 1480 deletions

View File

@ -8,5 +8,8 @@ jobs:
test:
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v1
with:
go-version: "1.16.4"
- uses: actions/checkout@v2
- run: ./make --disable-embedding-psiphon-config -t ./MOBILE/android/oonimkall.aar
- run: ./mk OONI_PSIPHON_TAGS="" ./MOBILE/android/oonimkall.aar

View File

@ -8,5 +8,8 @@ jobs:
test:
runs-on: macos-10.15
steps:
- uses: actions/setup-go@v1
with:
go-version: "1.16.4"
- uses: actions/checkout@v2
- run: ./make --disable-embedding-psiphon-config -t ./MOBILE/ios/oonimkall.framework.zip
- run: ./mk OONI_PSIPHON_TAGS="" XCODE_VERSION=12.4 ./MOBILE/ios/oonimkall.framework.zip

View File

@ -13,11 +13,11 @@ jobs:
echo $'{\n "experimental": true\n}' | sudo tee /etc/docker/daemon.json
sudo service docker restart
- uses: actions/checkout@v2
- run: ./make --disable-embedding-psiphon-config -t ./CLI/linux/amd64/ooniprobe
- run: ./mk OONI_PSIPHON_TAGS="" ./CLI/linux/amd64/ooniprobe
env:
DOCKER_CLI_EXPERIMENTAL: enabled
- run: ./smoketest.sh ./CLI/linux/amd64/ooniprobe
- run: ./make --disable-embedding-psiphon-config -t debian_amd64
- run: ./mk OONI_PSIPHON_TAGS="" DEBIAN_TILDE_VERSION=$GITHUB_RUN_NUMBER ./debian/amd64
- run: sudo apt-get install -y --no-install-recommends git python3 python3-requests python3-gnupg s3cmd
- run: |
for deb in *.deb; do
@ -35,12 +35,13 @@ jobs:
echo $'{\n "experimental": true\n}' | sudo tee /etc/docker/daemon.json
sudo service docker restart
- uses: actions/checkout@v2
- run: sudo apt-get install qemu-user-static
- run: ./make --disable-embedding-psiphon-config -t ./CLI/linux/arm64/ooniprobe
- run: sudo apt-get update -q
- run: sudo apt-get install -y qemu-user-static
- run: ./mk OONI_PSIPHON_TAGS="" ./CLI/linux/arm64/ooniprobe
env:
DOCKER_CLI_EXPERIMENTAL: enabled
- run: ./smoketest.sh ./CLI/linux/arm64/ooniprobe
- run: ./make --disable-embedding-psiphon-config -t debian_arm64
- run: ./mk OONI_PSIPHON_TAGS="" DEBIAN_TILDE_VERSION=$GITHUB_RUN_NUMBER ./debian/arm64
- run: sudo apt-get install -y --no-install-recommends git python3 python3-requests python3-gnupg s3cmd
- run: |
for deb in *.deb; do

View File

@ -8,6 +8,9 @@ jobs:
build:
runs-on: "macos-10.15"
steps:
- uses: actions/setup-go@v1
with:
go-version: "1.16.4"
- uses: actions/checkout@v2
- run: ./make --disable-embedding-psiphon-config -t ./CLI/darwin/amd64/ooniprobe
- run: ./mk OONI_PSIPHON_TAGS="" ./CLI/darwin/amd64/ooniprobe
- run: ./smoketest.sh ./CLI/darwin/amd64/ooniprobe

View File

@ -10,8 +10,11 @@ jobs:
test:
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v1
with:
go-version: "1.16.4"
- uses: actions/checkout@v2
- run: ./make --disable-embedding-psiphon-config -t miniooni
- run: ./mk OONI_PSIPHON_TAGS="" ./CLI/miniooni
- run: ./CLI/linux/amd64/miniooni --yes -nNi https://example.com web_connectivity

View File

@ -8,9 +8,12 @@ jobs:
build:
runs-on: "ubuntu-20.04"
steps:
- uses: actions/setup-go@v1
with:
go-version: "1.16.4"
- uses: actions/checkout@v2
- run: sudo apt install mingw-w64
- run: ./make --disable-embedding-psiphon-config -t ./CLI/windows/amd64/ooniprobe.exe
- run: ./mk OONI_PSIPHON_TAGS="" MINGW_W64_VERSION="9.3-win32" ./CLI/windows/amd64/ooniprobe.exe
- uses: actions/upload-artifact@v2
with:
name: ooniprobe.exe

View File

@ -1,15 +1,18 @@
#!/bin/sh
# This script is executed by `./make` when building inside
# This script is executed by `./mk` when building inside
# an Alpine Linux docker container. Using Alpine Linux, which
# uses musl libc, allows us to emit static binaries.
set -e
if [ "$GOARCH" = "" ]; then
echo 'fatal: $GOARCH is not set' 1>&2
exit 1
echo 'fatal: GOARCH is not set' 1>&2
exit 1
fi
set -x
apk update
apk upgrade
apk add --no-progress gcc git linux-headers musl-dev
CGO_ENABLED=1 GOOS=linux GOARCH=$GOARCH go build -o ./CLI/linux/$GOARCH/ \
-ldflags='-s -w -extldflags "-static"' "$@" ./cmd/ooniprobe
export GOPATH=$GOPATH
export CGO_ENABLED=1
export GOOS=linux
export GOARCH=$GOARCH
go build -o "./CLI/linux/$GOARCH/" -ldflags='-s -w -extldflags "-static"' "$@" ./cmd/ooniprobe

View File

@ -1,5 +1,5 @@
#!/bin/sh
# This script creates a Debian package. When run by `./make`, it
# This script creates a Debian package. When run by `./mk`, it
# is run inside a debian:stable container. It's fine to also
# run this script from any debian-like system, as long as the
# following ASSUMPTIONS are met:
@ -11,8 +11,8 @@
# architecture of the `ooniprobe` we are packaging.
if [ $# -gt 1 ]; then
echo "usage: $0 [run_number]" 1>&2
exit 1
echo "usage: $0 [run_number]" 1>&2
exit 1
fi
run_number=$1
@ -20,32 +20,32 @@ run_number=$1
# by the debian/ooniprobe-cli.install file.
rm -rf ./debian/bin
mkdir -p ./debian/bin
machine=`uname -m`
machine=$(uname -m)
goarch=""
case $machine in
x86_64)
cp ./CLI/linux/amd64/ooniprobe ./debian/bin
goarch=amd64
;;
aarch64)
cp ./CLI/linux/arm64/ooniprobe ./debian/bin
goarch=arm64
;;
*)
# TODO(bassosimone): here we probably want to further extend
# this script to support at least armv7.
echo "FATAL: unsupported machine: $machine" 1>&2
exit 1
;;
x86_64)
cp ./CLI/linux/amd64/ooniprobe ./debian/bin
goarch=amd64
;;
aarch64)
cp ./CLI/linux/arm64/ooniprobe ./debian/bin
goarch=arm64
;;
*)
# TODO(bassosimone): here we probably want to further extend
# this script to support at least armv7.
echo "FATAL: unsupported machine: $machine" 1>&2
exit 1
;;
esac
set -ex
# figure out the version number from the binary itself (which rests
# on the assumption that `uname -m` can run such a binary)
version=`./debian/bin/ooniprobe version`
if [ ! -z $run_number ]; then
version="${version}~${run_number}"
# on the assumption that we can run such a binary)
version=$(./debian/bin/ooniprobe version)
if [ -n "$run_number" ]; then
version="${version}~${run_number}"
fi
# The OONI_DEB_DRY_RUN is a semi-undocumented feature allowing
@ -58,7 +58,7 @@ $OONI_DEB_DRY_RUN apt-get build-dep -y --no-install-recommends .
# keep the original changelog file safe
$OONI_DEB_DRY_RUN cp ./debian/changelog ./debian/changelog.oocopy
$OONI_DEB_DRY_RUN dch -v $version "New version ${version}"
$OONI_DEB_DRY_RUN dch -v "$version" "New version ${version}"
$OONI_DEB_DRY_RUN dpkg-buildpackage -us -uc -b
# restore the original changelog file
@ -70,4 +70,4 @@ $OONI_DEB_DRY_RUN mv ../*.deb .
# install the package on the container as a smoke test to
# ensure that it is installable.
DEBIAN_FRONTEND=noninteractive dpkg -i ooniprobe-cli_${version}_${goarch}.deb
DEBIAN_FRONTEND=noninteractive dpkg -i "ooniprobe-cli_${version}_${goarch}.deb"

View File

@ -34,13 +34,13 @@ This will generate a binary called `ooniprobe` in the current directory.
## Android bindings
Make sure you have Python 3.8+ installed, then run:
Make sure you have GNU make installed, then run:
```bash
./make -t android
./mk android
```
Builds bindings for Android. (Add `----disable-embedding-psiphon-config` if you
Builds bindings for Android. (Add `OONI_PSIPHON_TAGS=""` if you
cannot clone private repositories in the https://github.com/ooni namespace.)
The generated bindings are (manually) pushed to the Maven Central package
@ -49,13 +49,13 @@ are published along with the release notes.
## iOS bindings
Make sure you have Python 3.8+ installed, then run:
Make sure you have GNU make installed, then run:
```bash
./make -t ios
./mk ios
```
Builds bindings for iOS. (Add `----disable-embedding-psiphon-config` if you
Builds bindings for iOS. (Add `OONI_PSIPHON_TAGS=""` if you
cannot clone private repositories in the https://github.com/ooni namespace.)
The generated bindings are (manually) added to GitHub releases. The instructions
@ -83,4 +83,5 @@ Create an issue according to [the routine release template](
https://github.com/ooni/probe/blob/master/.github/ISSUE_TEMPLATE/routine-sprint-releases.md)
and perform any item inside the check-list.
We build releases using `./make`, which requires Python3.8+.
We build releases using `./mk`, which requires GNU make. Try
the `./mk help|less` command for detailed usage.

1434
make

File diff suppressed because it is too large Load Diff

602
mk Executable file
View File

@ -0,0 +1,602 @@
#!/usr/bin/make -f
#quickhelp: Usage: ./mk [VARIABLE=VALUE ...] TARGET ...
.PHONY: usage
usage:
@cat mk | grep '^#quickhelp:' | sed -e 's/^#quickhelp://' -e 's/^\ *//'
# Most targets are .PHONY because whether to rebuild is controlled
# by golang. We expose to the user all the .PHONY targets.
#quickhelp:
#quickhelp: The `./mk list-targets` command lists all available targets.
.PHONY: list-targets
list-targets:
@cat mk | grep '^\.PHONY:' | sed -e 's/^\.PHONY://'
#quickhelp:
#quickhelp: The `./mk help` command provides detailed usage instructions. We
#quickhelp: recommend running `./mk help|less` to page its output.
.PHONY: help
help:
@cat mk | grep -E '^#(quick)?help:' | sed -E -e 's/^#(quick)?help://' -e s'/^\ //'
#help:
#help: The following variables control the build. You can specify them
#help: on the command line as a key-value pairs (see usage above).
#help:
#help: * ANDROID_CLI_SHA256 : the SHA256 of the Android CLI tools file. We always
#help: download the Linux version, which seems to work
#help: also on macOS (thank you, Java! :pray:).
ANDROID_CLI_SHA256 = 7a00faadc0864f78edd8f4908a629a46d622375cbe2e5814e82934aebecdb622
#help:
#help: * ANDROID_CLI_VERSION : the version of the Android CLI tools.
ANDROID_CLI_VERSION = 7302050
#help:
#help: * ANDROID_INSTALL_EXTRA : contains the android tools we install in addition
#help: to the NDK in order to build oonimkall.aar.
ANDROID_INSTALL_EXTRA = 'build-tools;29.0.3' 'platforms;android-30'
#help:
#help: * ANDROID_NDK_VERSION : Android NDK version.
ANDROID_NDK_VERSION = 22.1.7171670
#help:
#help: * DEBIAN_TILDE_VERSION : if non-empty, this should be "[0-9]+" and
#help: will be appended to the package version using
#help: a tilde, thus producing, e.g., "1.0~1234".
DEBIAN_TILDE_VERSION =
#help:
#help: * GIT_CLONE_DIR : directory where to clone repositories, by default
#help: set to `$HOME/.ooniprobe-build/src`.
GIT_CLONE_DIR = $(HOME)/.ooniprobe-build/src
# $(GIT_CLONE_DIR) is an internal target that creates $(GIT_CLONE_DIR).
$(GIT_CLONE_DIR):
mkdir -p $(GIT_CLONE_DIR)
#help:
#help: * GOLANG_DOCKER_GOCACHE : where to store golang's build cache to
#help: speed up subsequent Docker builds.
GOLANG_DOCKER_GOCACHE = $(HOME)/.ooniprobe-build/docker/gocache
#help:
#help: * GOLANG_DOCKER_GOPATH : GOPATH directory used by builds running
#help: inside docker to significantly speed
#help: up subsequent Docker based builds.
GOLANG_DOCKER_GOPATH := $(HOME)/.ooniprobe-build/docker/gopath
#help:
#help: * GOLANG_EXTRA_FLAGS : extra flags passed to `go build ...`, empty by
#help: default. Useful to pass flags to `go`, e.g.:
#help:
#help: ./mk GOLANG_EXTRA_FLAGS="-x -v" ./CLI/miniooni
GOLANG_EXTRA_FLAGS =
#help:
#help: * GOLANG_VERSION_NUMBER : the expected version number for golang.
GOLANG_VERSION_NUMBER = 1.16.4
#help:
#help: * GPG_USER : allows overriding the default GPG user used
#help: to sign binary releases, e.g.:
#help:
#help: ./mk GPG_USER=john@doe.com ooniprobe/windows
GPG_USER = simone@openobservatory.org
#help:
#help: * MINGW_W64_VERSION : the expected mingw-w64 version.
MINGW_W64_VERSION = 10.3.1
#help:
#help: * OONI_PSIPHON_TAGS : build tags for `go build -tags ...` that cause
#help: the build to embed a psiphon configuration file
#help: into the generated binaries. This build tag
#help: implies cloning the git@github.com:ooni/probe-private
#help: repository. If you do not have the permission to
#help: clone it, just clear this variable, e.g.:
#help:
#help: ./mk OONI_PSIPHON_TAGS="" ./CLI/miniooni
OONI_PSIPHON_TAGS = ooni_psiphon_config
#help:
#help: * OONI_ANDROID_HOME : directory where the Android SDK is downloaded
#help: and installed. You can point this to an existing
#help: copy of the SDK as long as (1) you have the
#help: right version of the command line tools, and
#help: (2) it's okay for us to install packages.
OONI_ANDROID_HOME = $(HOME)/.ooniprobe-build/sdk/android
#help:
#help: * XCODE_VERSION : the version of Xcode we expect.
XCODE_VERSION = 12.5
#quickhelp:
#quickhelp: The `./mk show-config` command shows the current value of the
#quickhelp: variables controlling the build.
.PHONY: show-config
show-config:
@echo "ANDROID_CLI_VERSION=$(ANDROID_CLI_VERSION)"
@echo "ANDROID_CLI_SHA256=$(ANDROID_CLI_SHA256)"
@echo "ANDROID_INSTALL_EXTRA=$(ANDROID_INSTALL_EXTRA)"
@echo "ANDROID_NDK_VERSION=$(ANDROID_NDK_VERSION)"
@echo "DEBIAN_TILDE_VERSION=$(DEBIAN_TILDE_VERSION)"
@echo "GIT_CLONE_DIR=$(GIT_CLONE_DIR)"
@echo "GOLANG_DOCKER_GOCACHE=$(GOLANG_DOCKER_GOCACHE)"
@echo "GOLANG_DOCKER_GOPATH=$(GOLANG_DOCKER_GOPATH)"
@echo "GOLANG_EXTRA_FLAGS=$(GOLANG_EXTRA_FLAGS)"
@echo "GOLANG_VERSION_NUMBER=$(GOLANG_VERSION_NUMBER)"
@echo "GPG_USER=$(GPG_USER)"
@echo "MINGW_W64_VERSION=$(MINGW_W64_VERSION)"
@echo "OONI_PSIPHON_TAGS=$(OONI_PSIPHON_TAGS)"
@echo "OONI_ANDROID_HOME=$(OONI_ANDROID_HOME)"
@echo "XCODE_VERSION=$(XCODE_VERSION)"
# GOLANG_VERSION_STRING is the expected version string. If we
# run a golang binary that does not emit this version string
# when running `go version`, we stop the build.
GOLANG_VERSION_STRING = go$(GOLANG_VERSION_NUMBER)
# GOLANG_DOCKER_IMAGE is the golang docker image we use for
# building for Linux systems. It is an Alpine based container
# so that we can easily build static binaries.
GOLANG_DOCKER_IMAGE = golang:$(GOLANG_VERSION_NUMBER)-alpine
# Cross-compiling miniooni from any system with Go installed is
# very easy, because it does not use any C code.
#help:
#help: The `./mk ./CLI/miniooni` command builds the miniooni experimental
#help: command line client for all the supported GOOS/GOARCH.
#help:
#help: You can also build the following subtargets:
.PHONY: ./CLI/miniooni
./CLI/miniooni: \
./CLI/darwin/amd64/miniooni \
./CLI/darwin/arm64/miniooni \
./CLI/linux/386/miniooni \
./CLI/linux/amd64/miniooni \
./CLI/linux/arm/miniooni \
./CLI/linux/arm64/miniooni \
./CLI/windows/386/miniooni.exe \
./CLI/windows/amd64/miniooni.exe
# All the miniooni targets build with CGO_ENABLED=0 such that the build
# succeeds when the GOOS/GOARCH is such that we aren't crosscompiling
# (e.g., targeting darwin/amd64 on darwin/amd64) _and_ there's no C compiler
# installed on the system. We can afford that since miniooni is pure Go.
#help:
#help: * `./mk ./CLI/darwin/amd64/miniooni`: darwin/amd64
.PHONY: ./CLI/darwin/amd64/miniooni
./CLI/darwin/amd64/miniooni: search/for/go maybe/copypsiphon
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -tags="$(OONI_PSIPHON_TAGS)" -ldflags="-s -w" $(GOLANG_EXTRA_FLAGS) -o $@ ./internal/cmd/miniooni
#help:
#help: * `./mk ./CLI/darwin/arm64/miniooni`: darwin/arm64
.PHONY: ./CLI/darwin/arm64/miniooni
./CLI/darwin/arm64/miniooni: search/for/go maybe/copypsiphon
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -tags="$(OONI_PSIPHON_TAGS)" -ldflags="-s -w" $(GOLANG_EXTRA_FLAGS) -o $@ ./internal/cmd/miniooni
# When building for Linux we use `-tags netgo` and `-extldflags -static` to produce
# a statically linked binary that completely bypasses libc.
#help:
#help: * `./mk ./CLI/linux/386/miniooni`: linux/386
.PHONY: ./CLI/linux/386/miniooni
./CLI/linux/386/miniooni: search/for/go maybe/copypsiphon
GOOS=linux GOARCH=386 CGO_ENABLED=0 go build -tags="netgo,$(OONI_PSIPHON_TAGS)" -ldflags="-s -w -extldflags -static" $(GOLANG_EXTRA_FLAGS) -o $@ ./internal/cmd/miniooni
#help:
#help: * `./mk ./CLI/linux/amd64/miniooni`: linux/amd64
.PHONY: ./CLI/linux/amd64/miniooni
./CLI/linux/amd64/miniooni: search/for/go maybe/copypsiphon
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -tags="netgo,$(OONI_PSIPHON_TAGS)" -ldflags="-s -w -extldflags -static" $(GOLANG_EXTRA_FLAGS) -o $@ ./internal/cmd/miniooni
# When building for GOARCH=arm, we always force GOARM=7 (i.e., armhf/armv7).
#help:
#help: * `./mk ./CLI/linux/arm/miniooni`: linux/arm
.PHONY: ./CLI/linux/arm/miniooni
./CLI/linux/arm/miniooni: search/for/go maybe/copypsiphon
GOOS=linux GOARCH=arm CGO_ENABLED=0 GOARM=7 go build -tags="netgo,$(OONI_PSIPHON_TAGS)" -ldflags="-s -w -extldflags -static" $(GOLANG_EXTRA_FLAGS) -o $@ ./internal/cmd/miniooni
#help:
#help: * `./mk ./CLI/linux/arm64/miniooni`: linux/arm64
.PHONY: ./CLI/linux/arm64/miniooni
./CLI/linux/arm64/miniooni: search/for/go maybe/copypsiphon
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -tags="netgo,$(OONI_PSIPHON_TAGS)" -ldflags="-s -w -extldflags -static" $(GOLANG_EXTRA_FLAGS) -o $@ ./internal/cmd/miniooni
#help:
#help: * `./mk ./CLI/windows/386/miniooni.exe`: windows/386
.PHONY: ./CLI/windows/386/miniooni.exe
./CLI/windows/386/miniooni.exe: search/for/go maybe/copypsiphon
GOOS=windows GOARCH=386 CGO_ENABLED=0 go build -tags="$(OONI_PSIPHON_TAGS)" -ldflags="-s -w" $(GOLANG_EXTRA_FLAGS) -o $@ ./internal/cmd/miniooni
#help:
#help: * `./mk ./CLI/windows/amd64/miniooni.exe`: windows/amd64
.PHONY: ./CLI/windows/amd64/miniooni.exe
./CLI/windows/amd64/miniooni.exe: search/for/go maybe/copypsiphon
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -tags="$(OONI_PSIPHON_TAGS)" -ldflags="-s -w" $(GOLANG_EXTRA_FLAGS) -o $@ ./internal/cmd/miniooni
#help:
#help: The `./mk ./CLI/ooniprobe/darwin` command builds the ooniprobe official
#help: command line client for darwin/amd64 and darwin/arm64. This process
#help: entails building ooniprobe and then GPG-signing the binaries.
#help:
#help: You can also build the following subtargets:
.PHONY: ./CLI/ooniprobe/darwin
./CLI/ooniprobe/darwin: \
./CLI/darwin/amd64/ooniprobe.asc \
./CLI/darwin/arm64/ooniprobe.asc
# ./CLI/darwin/amd64/ooniprobe.asc is an internal target for signing
.PHONY: ./CLI/darwin/amd64/ooniprobe.asc
./CLI/darwin/amd64/ooniprobe.asc: ./CLI/darwin/amd64/ooniprobe
rm -f $@ && gpg -abu $(GPG_USER) $<
# We force CGO_ENABLED=1 because in principle we may be cross compiling. In
# reality it's hard to see a macOS/darwin build not made on macOS.
#help:
#help: * `./mk ./CLI/darwin/amd64/ooniprobe`: darwin/amd64
.PHONY: ./CLI/darwin/amd64/ooniprobe
./CLI/darwin/amd64/ooniprobe: search/for/go maybe/copypsiphon
GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 go build -tags="$(OONI_PSIPHON_TAGS)" -ldflags="-s -w" $(GOLANG_EXTRA_FLAGS) -o $@ ./cmd/ooniprobe
# ./CLI/darwin/arm64/ooniprobe.asc is an internal target for signing
.PHONY: ./CLI/darwin/arm64/ooniprobe.asc
./CLI/darwin/arm64/ooniprobe.asc: ./CLI/darwin/arm64/ooniprobe
rm -f $@ && gpg -abu $(GPG_USER) $<
#help:
#help: * `./mk ./CLI/darwin/arm64/ooniprobe`: darwin/arm64
.PHONY: ./CLI/darwin/arm64/ooniprobe
./CLI/darwin/arm64/ooniprobe: search/for/go maybe/copypsiphon
GOOS=darwin GOARCH=arm64 CGO_ENABLED=1 go build -tags="$(OONI_PSIPHON_TAGS)" -ldflags="-s -w" $(GOLANG_EXTRA_FLAGS) -o $@ ./cmd/ooniprobe
#help:
#help: The `./mk ./debian` command builds the ooniprobe CLI
#help: debian package for amd64 and arm64.
#help:
#help: You can also build the following subtargets:
.PHONY: ./debian
./debian: \
./debian/amd64 \
./debian/arm64
#help:
#help: * `./mk ./debian/amd64`: debian/amd64
.PHONY: ./debian/amd64
# This extra .PHONY for linux/amd64 is to help printing targets 🤷.
.PHONY: ./CLI/linux/amd64/ooniprobe
./debian/amd64: search/for/docker ./CLI/linux/amd64/ooniprobe
docker pull --platform linux/amd64 debian:stable
docker run --platform linux/amd64 -v $(shell pwd):/ooni -w /ooni debian:stable ./CLI/linux/debian "$(DEBIAN_TILDE_VERSION)"
#help:
#help: * `./mk ./debian/arm64`: debian/arm64
.PHONY: ./debian/arm64
# This extra .PHONY for linux/arm64 is to help printing targets 🤷.
.PHONY: ./CLI/linux/arm64/ooniprobe
./debian/arm64: search/for/docker ./CLI/linux/arm64/ooniprobe
docker pull --platform linux/arm64 debian:stable
docker run --platform linux/arm64 -v $(shell pwd):/ooni -w /ooni debian:stable ./CLI/linux/debian "$(DEBIAN_TILDE_VERSION)"
#help:
#help: The `./mk ./CLI/ooniprobe/linux` command builds the ooniprobe official command
#help: line client for amd64 and arm64. This entails building and GPG signing.
#help:
#help: You can also build the following subtargets:
.PHONY: ./CLI/ooniprobe/linux
./CLI/ooniprobe/linux: \
./CLI/linux/amd64/ooniprobe.asc \
./CLI/linux/arm64/ooniprobe.asc
# ./CLI/linux/amd64/ooniprobe.asc is an internal task for signing.
.PHONY: ./CLI/linux/amd64/ooniprobe.asc
./CLI/linux/amd64/ooniprobe.asc: ./CLI/linux/amd64/ooniprobe
rm -f $@ && gpg -abu $(GPG_USER) $<
# Linux builds use Alpine and Docker so we are sure that we are statically
# linking to musl libc, thus making our binaries extremely portable.
#help:
#help: * `./mk ./CLI/linux/amd64/ooniprobe`: linux/amd64
.PHONY: ./CLI/linux/amd64/ooniprobe
./CLI/linux/amd64/ooniprobe: search/for/docker maybe/copypsiphon
docker pull --platform linux/amd64 $(GOLANG_DOCKER_IMAGE)
docker run --platform linux/amd64 -e GOPATH=/gopath -e GOARCH=amd64 -v $(GOLANG_DOCKER_GOCACHE)/amd64:/root/.cache/go-build -v $(GOLANG_DOCKER_GOPATH):/gopath -v $(shell pwd):/ooni -w /ooni $(GOLANG_DOCKER_IMAGE) ./CLI/linux/build -tags=netgo,$(OONI_PSIPHON_TAGS) $(GOLANG_EXTRA_FLAGS)
# ./CLI/linux/arm64/ooniprobe.asc is an internal task for signing.
.PHONY: ./CLI/linux/arm64/ooniprobe.asc
./CLI/linux/arm64/ooniprobe.asc: ./CLI/linux/arm64/ooniprobe
rm -f $@ && gpg -abu $(GPG_USER) $<
#help:
#help: * `./mk ./CLI/linux/arm64/ooniprobe`: linux/arm64
.PHONY: ./CLI/linux/arm64/ooniprobe
./CLI/linux/arm64/ooniprobe: search/for/docker maybe/copypsiphon
docker pull --platform linux/arm64 $(GOLANG_DOCKER_IMAGE)
docker run --platform linux/arm64 -e GOPATH=/gopath -e GOARCH=arm64 -v $(GOLANG_DOCKER_GOCACHE)/arm64:/root/.cache/go-build -v $(GOLANG_DOCKER_GOPATH):/gopath -v $(shell pwd):/ooni -w /ooni $(GOLANG_DOCKER_IMAGE) ./CLI/linux/build -tags=netgo,$(OONI_PSIPHON_TAGS) $(GOLANG_EXTRA_FLAGS)
#help:
#help: The `./mk ./CLI/ooniprobe/windows` command builds the ooniprobe official
#help: command line client for windows/386 and windows/amd64. This entails
#help: building and PGP signing the executables.
#help:
#help: You can also build the following subtargets:
.PHONY: ./CLI/ooniprobe/windows
./CLI/ooniprobe/windows: \
./CLI/windows/386/ooniprobe.exe.asc \
./CLI/windows/amd64/ooniprobe.exe.asc
# ./CLI/windows/386/ooniprobe.exe.asc is an internal signing target
.PHONY: ./CLI/windows/386/ooniprobe.exe.asc
./CLI/windows/386/ooniprobe.exe.asc: ./CLI/windows/386/ooniprobe.exe
rm -f $@ && gpg -abu $(GPG_USER) $<
#help:
#help: * `./mk ./CLI/windows/386/ooniprobe.exe`: windows/386
.PHONY: ./CLI/windows/386/ooniprobe.exe
./CLI/windows/386/ooniprobe.exe: search/for/go search/for/mingw-w64 maybe/copypsiphon
GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -tags="$(OONI_PSIPHON_TAGS)" -ldflags="-s -w" $(GOLANG_EXTRA_FLAGS) -o $@ ./cmd/ooniprobe
# ./CLI/windows/amd64/ooniprobe.exe.asc is an internal signing target
.PHONY: ./CLI/windows/amd64/ooniprobe.exe.asc
./CLI/windows/amd64/ooniprobe.exe.asc: ./CLI/windows/amd64/ooniprobe.exe
rm -f $@ && gpg -abu $(GPG_USER) $<
#help:
#help: * `./mk ./CLI/windows/amd64/ooniprobe.exe`: windows/amd64
.PHONY: ./CLI/windows/amd64/ooniprobe.exe
./CLI/windows/amd64/ooniprobe.exe: search/for/go search/for/mingw-w64 maybe/copypsiphon
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build -tags="$(OONI_PSIPHON_TAGS)" -ldflags="-s -w" $(GOLANG_EXTRA_FLAGS) -o $@ ./cmd/ooniprobe
#help:
#help: The `./mk ./MOBILE/android` command builds the oonimkall library for Android.
#help:
#help: You can also build the following subtargets:
.PHONY: ./MOBILE/android
./MOBILE/android: search/for/gpg search/for/jar ./MOBILE/android/oonimkall.aar
cp ./MOBILE/android/oonimkall.aar ./MOBILE/android/oonimkall-$(OONIMKALL_V).aar
cp ./MOBILE/android/oonimkall-sources.jar ./MOBILE/android/oonimkall-$(OONIMKALL_V)-sources.jar
cat ./MOBILE/template.pom | sed -e "s/@VERSION@/$(OONIMKALL_V)/g" > ./MOBILE/android/oonimkall-$(OONIMKALL_V).pom
gpg -abu $(GPG_USER) ./MOBILE/android/oonimkall-$(OONIMKALL_V).aar
gpg -abu $(GPG_USER) ./MOBILE/android/oonimkall-$(OONIMKALL_V)-sources.jar
gpg -abu $(GPG_USER) ./MOBILE/android/oonimkall-$(OONIMKALL_V).pom
cd ./MOBILE/android && jar -cf bundle.jar oonimkall-$(OONIMKALL_V).aar oonimkall-$(OONIMKALL_V).aar.asc oonimkall-$(OONIMKALL_V)-sources.jar oonimkall-$(OONIMKALL_V)-sources.jar.asc oonimkall-$(OONIMKALL_V).pom oonimkall-$(OONIMKALL_V).pom.asc
#help:
#help: * `./mk ./MOBILE/android/oonimkall.aar`: the AAR
.PHONY: ./MOBILE/android/oonimkall.aar
./MOBILE/android/oonimkall.aar: android/sdk ooni/go maybe/copypsiphon
PATH=$(OONIGODIR)/bin:$$PATH $(MAKE) -f mk __android_build_with_ooni_go
# GOMOBILE is the full path location to the gomobile binary. We want to
# execute this command every time, because its output may depend on context,
# for this reason WE ARE NOT using `:=`.
GOMOBILE = $(shell go env GOPATH)/bin/gomobile
# Here we use ooni/go to work around https://github.com/ooni/probe/issues/1444
__android_build_with_ooni_go: search/for/go
go get -u golang.org/x/mobile/cmd/gomobile
$(GOMOBILE) init
PATH=$(shell go env GOPATH)/bin:$$PATH ANDROID_HOME=$(OONI_ANDROID_HOME) ANDROID_NDK_HOME=$(OONI_ANDROID_HOME)/ndk/$(ANDROID_NDK_VERSION) $(GOMOBILE) bind -target android -o ./MOBILE/android/oonimkall.aar -tags="$(OONI_PSIPHON_TAGS)" -ldflags '-s -w' $(GOLANG_EXTRA_FLAGS) ./pkg/oonimkall
#help:
#help: The `./mk ./MOBILE/ios` command builds the oonimkall library for iOS.
#help:
#help: You can also build the following subtargets:
.PHONY: ./MOBILE/ios
./MOBILE/ios: \
./MOBILE/ios/oonimkall.framework.zip \
./MOBILE/ios/oonimkall.podspec
#help:
#help: * `./mk ./MOBILE/ios/oonimkall.framework.zip`: zip the framework
.PHONY: ./MOBILE/ios/oonimkall.framework.zip
./MOBILE/ios/oonimkall.framework.zip: search/for/zip ./MOBILE/ios/oonimkall.framework
cd ./MOBILE/ios && rm -rf oonimkall.framework.zip
cd ./MOBILE/ios && zip -yr oonimkall.framework.zip oonimkall.framework
#help:
#help: * `./mk ./MOBILE/ios/framework`: the framework
.PHONY: ./MOBILE/ios/oonimkall.framework
./MOBILE/ios/oonimkall.framework: search/for/go search/for/xcode
go get -u golang.org/x/mobile/cmd/gomobile
$(GOMOBILE) init
PATH=$(shell go env GOPATH)/bin:$$PATH $(GOMOBILE) bind -target ios -o $@ -tags="$(OONI_PSIPHON_TAGS)" -ldflags '-s -w' $(GOLANG_EXTRA_FLAGS) ./pkg/oonimkall
#help:
#help: * `./mk ./MOBILE/ios/oonimkall.podspec`: the podspec
.PHONY: ./MOBILE/ios/oonimkall.podspec
./MOBILE/ios/oonimkall.podspec: ./MOBILE/template.podspec
cat $< | sed -e "s/@VERSION@/$(OONIMKALL_V)/g" -e "s/@RELEASE@/$(OONIMKALL_R)/g" > $@
# important: OONIMKALL_V and OONIMKALL_R MUST be expanded just once so we use `:=`
OONIMKALL_V := $(shell date -u +%Y.%m.%d-%H%M%S)
OONIMKALL_R := $(shell git describe --tags || echo '0.0.0-dev')
#help:
#help: The following commands check for the availability of dependencies:
# TODO(bassosimone): make checks more robust?
#help:
#help: * `./mk search/for/bash`: checks for bash
.PHONY: search/for/bash
search/for/bash:
@printf "checking for bash... "
@command -v bash || { echo "not found"; exit 1; }
#help:
#help: * `./mk search/for/curl`: checks for curl
.PHONY: search/for/curl
search/for/curl:
@printf "checking for curl... "
@command -v curl || { echo "not found"; exit 1; }
#help:
#help: * `./mk search/for/docker`: checks for docker
.PHONY: search/for/docker
search/for/docker:
@printf "checking for docker... "
@command -v docker || { echo "not found"; exit 1; }
#help:
#help: * `./mk search/for/git`: checks for git
.PHONY: search/for/git
search/for/git:
@printf "checking for git... "
@command -v git || { echo "not found"; exit 1; }
#help:
#help: * `./mk search/for/gpg`: checks for gpg
.PHONY: search/for/gpg
search/for/gpg:
@printf "checking for gpg... "
@command -v gpg || { echo "not found"; exit 1; }
#help:
#help: * `./mk search/for/jar`: checks for jar
.PHONY: search/for/jar
search/for/jar:
@printf "checking for jar... "
@command -v jar || { echo "not found"; exit 1; }
#help:
#help: * `./mk search/for/java`: checks for java
.PHONY: search/for/java
search/for/java:
@printf "checking for java... "
@command -v java || { echo "not found"; exit 1; }
#help:
#help: * `./mk search/for/go`: checks for go
.PHONY: search/for/go
search/for/go:
@printf "checking for go... "
@command -v go || { echo "not found"; exit 1; }
@printf "checking for go version... "
@echo $(__GOVERSION_REAL)
@[ "$(GOLANG_VERSION_STRING)" = "$(__GOVERSION_REAL)" ] || { echo "fatal: go version must be $(GOLANG_VERSION_STRING) instead of $(__GOVERSION_REAL)"; exit 1; }
# __GOVERSION_REAL is the go version reported by the go binary (we
# SHOULD NOT cache this value so we ARE NOT using `:=`)
__GOVERSION_REAL = $(shell go version | awk '{print $$3}')
#help:
#help: * `./mk search/for/mingw-w64`: checks for mingw-w64
.PHONY: search/for/mingw-w64
search/for/mingw-w64:
@printf "checking for x86_64-w64-mingw32-gcc... "
@command -v x86_64-w64-mingw32-gcc || { echo "not found"; exit 1; }
@printf "checking for x86_64-w64-mingw32-gcc version... "
@echo $(__MINGW32_AMD64_VERSION)
@[ "$(MINGW_W64_VERSION)" = "$(__MINGW32_AMD64_VERSION)" ] || { echo "fatal: x86_64-w64-mingw32-gcc version must be $(MINGW_W64_VERSION) instead of $(__MINGW32_AMD64_VERSION)"; exit 1; }
@printf "checking for i686-w64-mingw32-gcc... "
@command -v i686-w64-mingw32-gcc || { echo "not found"; exit 1; }
@printf "checking for i686-w64-mingw32-gcc version... "
@echo $(__MINGW32_386_VERSION)
@[ "$(MINGW_W64_VERSION)" = "$(__MINGW32_386_VERSION)" ] || { echo "fatal: i686-w64-mingw32-gcc version must be $(MINGW_W64_VERSION) instead of $(__MINGW32_386_VERSION)"; exit 1; }
# __MINGW32_AMD64_VERSION and __MINGW32_386_VERSION are the versions
# reported by the amd64 and 386 mingw binaries.
__MINGW32_AMD64_VERSION = $(shell x86_64-w64-mingw32-gcc --version | sed -n 1p | awk '{print $$3}')
__MINGW32_386_VERSION = $(shell i686-w64-mingw32-gcc --version | sed -n 1p | awk '{print $$3}')
#help:
#help: * `./mk search/for/shasum`: checks for shasum
.PHONY: search/for/shasum
search/for/shasum:
@printf "checking for shasum... "
@command -v shasum || { echo "not found"; exit 1; }
#help:
#help: * `./mk search/for/xcode`: checks for Xcode
.PHONY: search/for/xcode
search/for/xcode:
@printf "checking for xcodebuild... "
@command -v xcodebuild || { echo "not found"; exit 1; }
@printf "checking for Xcode version... "
@echo $(__XCODEVERSION_REAL)
@[ "$(XCODE_VERSION)" = "$(__XCODEVERSION_REAL)" ] || { echo "fatal: Xcode version must be $(XCODE_VERSION) instead of $(__XCODEVERSION_REAL)"; exit 1; }
# __XCODEVERSION_REAL is the version of Xcode obtained using xcodebuild
__XCODEVERSION_REAL = `xcodebuild -version | grep ^Xcode | awk '{print $$2}'`
#help:
#help: * `./mk search/for/unzip`: checks for unzip
.PHONY: search/for/unzip
search/for/unzip:
@printf "checking for unzip... "
@command -v unzip || { echo "not found"; exit 1; }
#help:
#help: * `./mk search/for/zip`: checks for zip
.PHONY: search/for/zip
search/for/zip:
@printf "checking for zip... "
@command -v zip || { echo "not found"; exit 1; }
#help:
#help: The `./mk maybe/copypsiphon` command copies the private psiphon config
#help: file into the current tree unless `$(OONI_PSIPHON_TAGS)` is empty.
.PHONY: maybe/copypsiphon
maybe/copypsiphon: search/for/git
test -z "$(OONI_PSIPHON_TAGS)" || $(MAKE) -f mk $(OONIPRIVATE)
test -z "$(OONI_PSIPHON_TAGS)" || cp $(OONIPRIVATE)/psiphon-config.key ./internal/engine
test -z "$(OONI_PSIPHON_TAGS)" || cp $(OONIPRIVATE)/psiphon-config.json.age ./internal/engine
# OONIPRIVATE is the directory where we clone the private repository.
OONIPRIVATE = $(GIT_CLONE_DIR)/github.com/ooni/probe-private
# OONIPRIVATE_REPO is the private repository URL.
OONIPRIVATE_REPO = git@github.com:ooni/probe-private
# $(OONIPRIVATE) clones the private repository in $(GIT_CLONE_DIR)
$(OONIPRIVATE): search/for/git $(GIT_CLONE_DIR)
test -d $(OONIPRIVATE) || $(MAKE) -f mk __really_clone_private_repo
__really_clone_private_repo:
git clone $(OONIPRIVATE_REPO) $(OONIPRIVATE)
#help:
#help: The `./mk ooni/go` command builds the latest version of ooni/go.
.PHONY: ooni/go
ooni/go: search/for/bash search/for/git search/for/go $(OONIGODIR)
test -d $(OONIGODIR) || git clone -b ooni --single-branch --depth 8 $(OONIGO_REPO) $(OONIGODIR)
cd $(OONIGODIR) && git pull --ff-only
cd $(OONIGODIR)/src && ./make.bash
# OONIGODIR is the directory in which we clone ooni/go
OONIGODIR = $(GIT_CLONE_DIR)/github.com/ooni/go
# OONIGO_REPO is the repository for ooni/go
OONIGO_REPO = https://github.com/ooni/go
#help:
#help: The `./mk android/sdk` command ensures we are using the
#help: correct version of the Android sdk.
.PHONY: android/sdk
android/sdk: search/for/java
test -d $(OONI_ANDROID_HOME) || $(MAKE) -f mk android/sdk/download
echo "Yes" | $(__ANDROID_SDKMANAGER) --install $(ANDROID_INSTALL_EXTRA) 'ndk;$(ANDROID_NDK_VERSION)'
# __ANDROID_SKDMANAGER is the path to android's sdkmanager tool
__ANDROID_SDKMANAGER = $(OONI_ANDROID_HOME)/cmdline-tools/$(ANDROID_CLI_VERSION)/bin/sdkmanager
# See https://stackoverflow.com/a/61176718 to understand why
# we need to reorganize the directories like this:
#help:
#help: The `./mk android/sdk/download` unconditionally downloads the
#help: Android SDK at `$(OONI_ANDROID_HOME)`.
android/sdk/download: search/for/curl search/for/java search/for/shasum search/for/unzip
curl -fsSLO https://dl.google.com/android/repository/$(__ANDROID_CLITOOLS_FILE)
echo "$(ANDROID_CLI_SHA256) $(__ANDROID_CLITOOLS_FILE)" > __SHA256
shasum --check __SHA256
rm -f __SHA256
unzip $(__ANDROID_CLITOOLS_FILE)
rm $(__ANDROID_CLITOOLS_FILE)
mkdir -p $(OONI_ANDROID_HOME)/cmdline-tools
mv cmdline-tools $(OONI_ANDROID_HOME)/cmdline-tools/$(ANDROID_CLI_VERSION)
# __ANDROID_CLITOOLS_FILE is the file name of the android cli tools zip
__ANDROID_CLITOOLS_FILE = commandlinetools-linux-$(ANDROID_CLI_VERSION)_latest.zip