feat(make): build ooniprobe for darwin, windows, and linux (#328)

In https://github.com/ooni/probe/issues/1466, a user is asking
about arm64 builds for Debian. We already had some code for that
in https://github.com/ooni/probe-cli/pull/311. Let us adapt the
code to the `./make` script to have arm64 builds.

While there, also adapt the code for darwin and windows.
This commit is contained in:
Simone Basso 2021-05-05 12:12:34 +02:00 committed by GitHub
parent 5738c07aff
commit eb43c7994a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 198 additions and 13 deletions

View File

@ -1 +1,2 @@
/miniooni
/ooniprobe

12
CLI/linux/build Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
set -e
if [ "$GOARCH" = "" ]; then
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

198
make
View File

@ -1094,6 +1094,19 @@ class MiniOONILinux:
engine.run(cmdline)
# MINIOONI_TARGETS contains all miniooni targets
MINIOONI_TARGETS: List[Target] = [
MiniOONIDarwinOrWindows("darwin", "amd64"),
MiniOONIDarwinOrWindows("darwin", "arm64"),
MiniOONILinux("386"),
MiniOONILinux("amd64"),
MiniOONILinux("arm"),
MiniOONILinux("arm64"),
MiniOONIDarwinOrWindows("windows", "386"),
MiniOONIDarwinOrWindows("windows", "amd64"),
]
class MiniOONI:
"""MiniOONI is the top-level 'miniooni' target."""
@ -1103,31 +1116,190 @@ class MiniOONI:
return self.__name
def build(self, engine: Engine, options: Options) -> None:
for builder in (
MiniOONIDarwinOrWindows("darwin", "amd64"),
MiniOONIDarwinOrWindows("darwin", "arm64"),
MiniOONILinux("386"),
MiniOONILinux("amd64"),
MiniOONILinux("arm"),
MiniOONILinux("arm64"),
MiniOONIDarwinOrWindows("windows", "386"),
MiniOONIDarwinOrWindows("windows", "amd64"),
):
builder.build(engine, options)
for target in MINIOONI_TARGETS:
target.build(engine, options)
TARGETS: List[Target] = [
class OONIProbeLinux:
"""OONIProbeLinux builds ooniprobe for Linux."""
def __init__(self, goarch: str):
self.__name = os.path.join(".", "CLI", "linux", goarch, "ooniprobe")
self.__arch = goarch
def name(self) -> str:
return self.__name
def build(self, engine: Engine, options: Options) -> None:
if os.path.isfile(self.__name) and not options.dry_run():
log("\n./make: {}: already built".format(self.__name))
return
ooprivate = OONIProbePrivate()
ooprivate.build(engine, options)
log("\n./make: building {}...".format(self.__name))
ooprivate.copyfiles(engine, options)
engine.require("docker")
# make sure we have the latest version of the container image
engine.run(
[
"docker",
"pull",
"--platform",
"linux/{}".format(self.__arch),
"golang:{}-alpine".format(goversion()),
]
)
# then run the build inside the container
cmdline = [
"docker",
"run",
"--platform",
"linux/{}".format(self.__arch),
"-e",
"GOARCH={}".format(self.__arch),
"-it",
"-v",
"{}:/ooni".format(os.getcwd()),
"-w",
"/ooni",
"golang:{}-alpine".format(goversion()),
os.path.join(".", "CLI", "linux", "build"),
]
if options.debugging():
cmdline.append("-x")
if options.verbose():
cmdline.append("-v")
if not options.disable_embedding_psiphon_config():
cmdline.append("-tags=ooni_psiphon_config,netgo")
else:
cmdline.append("-tags=netgo")
engine.run(cmdline)
class OONIProbeWindows:
"""OONIProbeWindows builds ooniprobe for Windows."""
def __init__(self, goarch: str):
self.__name = os.path.join(".", "CLI", "windows", goarch, "ooniprobe.exe")
self.__arch = goarch
def name(self) -> str:
return self.__name
def _gcc(self) -> str:
if self.__arch == "amd64":
return "x86_64-w64-mingw32-gcc"
if self.__arch == "386":
return "i686-w64-mingw32-gcc"
raise NotImplementedError
def build(self, engine: Engine, options: Options) -> None:
if os.path.isfile(self.__name) and not options.dry_run():
log("\n./make: {}: already built".format(self.__name))
return
ooprivate = OONIProbePrivate()
ooprivate.build(engine, options)
gogo = SDKGolangGo()
gogo.build(engine, options)
log("\n./make: building {}...".format(self.__name))
ooprivate.copyfiles(engine, options)
cmdline = [
"go",
"build",
"-o",
self.__name,
"-ldflags=-s -w",
]
if options.debugging():
cmdline.append("-x")
if options.verbose():
cmdline.append("-v")
if not options.disable_embedding_psiphon_config():
cmdline.append("-tags=ooni_psiphon_config")
cmdline.append("./cmd/ooniprobe")
with Environ(engine, "GOOS", "windows"):
with Environ(engine, "GOARCH", self.__arch):
with Environ(engine, "CGO_ENABLED", "1"):
with Environ(engine, "CC", self._gcc()):
with AugmentedPath(engine, gogo.binpath()):
engine.require(self._gcc(), "go")
engine.run(cmdline)
class OONIProbeDarwin:
"""OONIProbeDarwin builds ooniprobe for macOS."""
def __init__(self, goarch: str):
self.__name = os.path.join(".", "CLI", "darwin", goarch, "ooniprobe")
self.__arch = goarch
def name(self) -> str:
return self.__name
def build(self, engine: Engine, options: Options) -> None:
if os.path.isfile(self.__name) and not options.dry_run():
log("\n./make: {}: already built".format(self.__name))
return
ooprivate = OONIProbePrivate()
ooprivate.build(engine, options)
gogo = SDKGolangGo()
gogo.build(engine, options)
log("\n./make: building {}...".format(self.__name))
ooprivate.copyfiles(engine, options)
cmdline = [
"go",
"build",
"-o",
self.__name,
"-ldflags=-s -w",
]
if options.debugging():
cmdline.append("-x")
if options.verbose():
cmdline.append("-v")
if not options.disable_embedding_psiphon_config():
cmdline.append("-tags=ooni_psiphon_config")
cmdline.append("./cmd/ooniprobe")
with Environ(engine, "GOOS", "darwin"):
with Environ(engine, "GOARCH", self.__arch):
with Environ(engine, "CGO_ENABLED", "1"):
with AugmentedPath(engine, gogo.binpath()):
engine.require("gcc", "go")
engine.run(cmdline)
# OONIPROBE_TARGETS contains all the ooniprobe targets
OONIPROBE_TARGETS: List[Target] = [
OONIProbeDarwin("amd64"),
OONIProbeDarwin("arm64"),
OONIProbeLinux("amd64"),
OONIProbeLinux("arm64"),
OONIProbeWindows("amd64"),
OONIProbeWindows("386"),
]
# MOBILE_TARGETS contains the top-level mobile targets.
MOBILE_TARGETS: List[Target] = [
Android(),
iOS(),
]
# EXTRA_TARGETS contains extra top-level targets.
EXTRA_TARGETS: List[Target] = [
MiniOONI(),
OONIMKAllAAR(),
OONIMKAllFrameworkZip(),
]
# VISIBLE_TARGETS contains all the visible-from-CLI targets
VISIBLE_TARGETS: List[Target] = (
OONIPROBE_TARGETS + MOBILE_TARGETS + EXTRA_TARGETS + MINIOONI_TARGETS
)
def main() -> None:
"""main function"""
toptargets: Dict[str, Target] = dict((t.name(), t) for t in TARGETS)
toptargets: Dict[str, Target] = dict((t.name(), t) for t in VISIBLE_TARGETS)
options = ConfigFromCLI.parse(list(toptargets.keys()))
engine = new_engine(options)
# note that we check whether the target is known in parse()