From 5ed2db24a90fb953b4c03569eae2df0e4c1903fc Mon Sep 17 00:00:00 2001 From: OscarSotoSanchez Date: Sat, 18 Jul 2026 18:42:05 +0200 Subject: [PATCH] Document and script building the native bridge for older Linux The native bridge libraries bundled in the JAR are compiled on Ubuntu 24.04, so they require GLIBC_2.32 and a libstdc++ exporting GLIBCXX_3.4.32 (a GCC 13+ runtime). On older hosts (e.g. Ubuntu 20.04: glibc 2.31 / GLIBCXX 3.4.28, and also Ubuntu 22.04, whose libstdc++ only reaches GLIBCXX_3.4.30) the first BRKGA call fails to load the bridge with "Cannot open library: /tmp/brkga-native-*/libbrkga_bridge_1.so". Nothing in the docs covered this. Add a way to build a compatible bridge locally and pick it up transparently: - scripts/build_brkga_native.sh: standalone helper that clones the published tag and builds the bridge inside an older base image (default ubuntu:20.04) with g++-13 from the ubuntu-toolchain-r PPA. It statically links libstdc++/libgcc by folding the flags into CXX ("-static-libstdc++ -static-libgcc"), so the result links against an old-enough glibc and carries its own C++ runtime, needing no host GLIBCXX. The base image (IMAGE), objective counts (TUPLE_NS), generic bridge (GENERIC), mating mode, extra-blob capacity and output directory (OUT_DIR) are all parametrizable; inputs are validated up front and the temporary clone is cleaned up on exit. - docs/JAVA_GUIDE.md: new "Running on an older Linux" section explaining the symptom, exactly which glibc/GLIBCXX thresholds are affected (with a table showing that release date is not the criterion), and two build routes (Docker and a local toolchain). Pointers added from "Installing", "Requirements and platform", the root README and the examples README. - .gitignore: ignore the locally built native/ output directories. Verified end-to-end on Ubuntu 20.04: the built libbrkga_bridge_1.so needs at most GLIBC_2.29 and no libstdc++.so.6, and the MainMinimal example runs against it via examples/native/ with no extra flags. --- .gitignore | 4 + README.md | 8 +- brkga_mp_ipr_java/docs/JAVA_GUIDE.md | 153 +++++++++++++++++++++- examples/README.md | 10 ++ scripts/build_brkga_native.sh | 186 +++++++++++++++++++++++++++ 5 files changed, 357 insertions(+), 4 deletions(-) create mode 100755 scripts/build_brkga_native.sh diff --git a/.gitignore b/.gitignore index 999b8f8..8e1fc35 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,7 @@ brkga_mp_ipr_java/bench/out/ # Recompiled native libraries produced via Docker out/ + +# Locally built native libraries (older-glibc workflow, scripts/build_brkga_native.sh) +/native/ +examples/native/ diff --git a/README.md b/README.md index 1c55b02..7536811 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,12 @@ git submodule update --init ``` Run your app with native access enabled: -`java --enable-native-access=ALL-UNNAMED ...`. Linux x86-64 binaries are bundled; -for other platforms or custom builds, see *Recompiling* in the Java guide. +`java --enable-native-access=ALL-UNNAMED ...`. Linux x86-64 binaries are bundled +(they need glibc ≥ 2.32 and a libstdc++ exporting GLIBCXX_3.4.32 or newer); +for other platforms, an older Linux, or custom builds, see +[*Recompiling*](brkga_mp_ipr_java/docs/JAVA_GUIDE.md#recompiling-the-native-library) +and [*Running on an older Linux*](brkga_mp_ipr_java/docs/JAVA_GUIDE.md#running-on-an-older-linux-glibc--glibcxx-too-new) +in the Java guide. ## Documentation diff --git a/brkga_mp_ipr_java/docs/JAVA_GUIDE.md b/brkga_mp_ipr_java/docs/JAVA_GUIDE.md index 421da7e..dcc832f 100644 --- a/brkga_mp_ipr_java/docs/JAVA_GUIDE.md +++ b/brkga_mp_ipr_java/docs/JAVA_GUIDE.md @@ -26,6 +26,7 @@ type. - [Runtime flags and the bridge library](#runtime-flags-and-the-bridge-library) - [Number of objectives](#number-of-objectives) - [Recompiling the native library](#recompiling-the-native-library) +- [Running on an older Linux (GLIBC / GLIBCXX too new)](#running-on-an-older-linux-glibc--glibcxx-too-new) - [Keeping extra data in the chromosome](#keeping-extra-data-in-the-chromosome) - [Writing a fast decoder](#writing-a-fast-decoder) - [Performance](#performance) @@ -59,6 +60,12 @@ temporary file and loads it. You only need the toolchain (or Docker) if you want to **recompile** the native library for advanced options — see [Recompiling the native library](#recompiling-the-native-library). +> **On a system whose glibc/libstdc++ are too old** (glibc < 2.32 or a libstdc++ +> that does not export GLIBCXX_3.4.32) the bundled binary may fail to load with +> `Cannot open library: /tmp/brkga-native-*/libbrkga_bridge_1.so` (the underlying +> reason is the too-new `GLIBC_2.32` / `GLIBCXX_3.4.32`). Build a compatible bridge +> locally — see [Running on an older Linux](#running-on-an-older-linux-glibc--glibcxx-too-new). + --- ## Requirements and platform @@ -70,6 +77,9 @@ to **recompile** the native library for advanced options — see - **Linux x86-64.** The bundled native binaries target this platform. On other platforms you must build your own (the loader will report that no binary applies); see [Recompiling the native library](#recompiling-the-native-library). + The bundled binaries need **glibc ≥ 2.32 and a libstdc++ exporting + GLIBCXX_3.4.32 or newer**; on a system with older versions, build them locally — + see [Running on an older Linux](#running-on-an-older-linux-glibc--glibcxx-too-new). - Your build tool (Maven/Gradle) to pull the dependency. **To build the wrapper from source / recompile the native core** (maintainers, @@ -278,8 +288,10 @@ make -C brkga_mp_ipr_java/native clean make -C brkga_mp_ipr_java/native all MATING=MATING_FULL_SPEED TUPLE_NS="1 2 3 8" EXTRA_CAP=16 CAP=32 ``` -`-Dbrkga.bridge.dir` always takes precedence over the binaries bundled in the JAR, -so a recompiled set transparently replaces them. +For each requested filename, `-Dbrkga.bridge.dir` takes precedence over the +binary bundled in the JAR. If the file is absent from that directory, the loader +falls back to the bundled version, so place a complete custom set there when the +bundled binaries cannot run on the host. > For **N > 20** you must also raise `CAP` (and the `Brkga.CAP` constant if you > rebuild the wrapper) to extend the generic binary, or build a dedicated tuple @@ -287,6 +299,143 @@ so a recompiled set transparently replaces them. --- +## Running on an older Linux (GLIBC / GLIBCXX too new) + +### The symptom + +The native binaries bundled in the JAR are compiled on **Ubuntu 24.04**, so they +require **`GLIBC_2.32`** and **`GLIBCXX_3.4.32`**. On an older host — for example +Ubuntu 20.04, which ships glibc 2.31 / GLIBCXX 3.4.28 — the first BRKGA call +(`Brkga.single()` / `Brkga.multi()` / `forObjectives(...)`, which is where the +bridge is loaded) throws. Your application sees only the top-level message — the +JVM does **not** print the reason: + +``` +java.lang.IllegalArgumentException: Cannot open library: /tmp/brkga-native-/libbrkga_bridge_1.so +``` + +(the examples print it as `Exception Occurred: Cannot open library: /tmp/brkga-native-…/libbrkga_bridge_1.so`). + +The real cause is the too-new glibc/libstdc++. To confirm it, extract the bundled +`.so` and inspect it with `ldd` — you will see the missing versions: + +```console +$ ldd libbrkga_bridge_1.so + ... /lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.32' not found ... + ... /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found ... +``` + +If you see `Cannot open library: …/libbrkga_bridge_*.so` on a Linux older than +Ubuntu 24.04, this is almost certainly why — build the bridge locally as below. + +### Which systems are affected (and which are not) + +The real requirement is **not** "the Ubuntu 24.04 distribution"; it is **two +version thresholds, both of which must be met**: + +- **`glibc ≥ 2.32`**, and +- a **libstdc++ exporting `GLIBCXX_3.4.32` or newer**. This symbol version first + appeared in GCC 13.2 (`GLIBCXX_3.4.31` = GCC 13.1, `GLIBCXX_3.4.33` = GCC 14). + Ubuntu 24.04 is the first Ubuntu LTS whose default runtime meets this threshold. + +Because glibc and libstdc++ are **backward-compatible** (a newer library still +exports the older symbol versions), any system **at or above** both thresholds +loads the bundled binary fine. Installing a newer GCC/libstdc++ alone is not +enough when the host glibc is still below 2.32; both checks are independent. + +Watch out for the intuition "newer release date = fine": what matters is the +libstdc++ version, not how recent the distro is. For example **Ubuntu 22.04** +has glibc 2.35 (≥ 2.32, fine) but its default libstdc++ is from GCC 12, i.e. only +GLIBCXX_3.4.30 (< 3.4.32) — so it **also fails**, on the GLIBCXX side. + +| System | glibc | GLIBCXX (libstdc++) | Loads the bundled `.so`? | +|---|---|---|---| +| Ubuntu 24.04 | 2.39 ✅ | 3.4.32 ✅ | ✅ yes | +| Other distributions | ≥ 2.32 ✅ | ≥ 3.4.32 ✅ | ✅ yes | +| Ubuntu 22.04 | 2.35 ✅ | 3.4.30 ❌ | ❌ no (GLIBCXX too old) | +| Ubuntu 20.04 | 2.31 ❌ | 3.4.28 ❌ | ❌ no | + +If your system is in a ❌ row, build the bridge locally as below. + +### The fix + +Build the bridge yourself so it targets your host. Two things make +the result run on an old system: + +1. **Compile against an old-enough glibc** — either directly on the old host, or + inside an old base image. A newer glibc cannot be "downgraded" by a flag, so + the [*Recompiling the native library*](#recompiling-the-native-library) Docker + route (base `gcc:13`) does **not** help here: its glibc is newer still. +2. **Statically link the C++ runtime** with `-static-libstdc++ -static-libgcc`, + so the binary carries its own libstdc++ and no longer depends on the host's + `GLIBCXX`. The Makefile compiles with `$(CXX)`, so the simplest way to inject + those flags (keeping all its tuned optimization flags) is to fold them into + `CXX`: `CXX="g++-13 -static-libstdc++ -static-libgcc"`. + +> **Toolchain note.** The bridge needs a real C++20 standard library +> (``, and `operator<<` for `std::chrono::duration`), so **g++ 13** is +> required — older compilers on old distros (g++-9/10) are not enough. + +### Route A — Docker (no local C++ toolchain) + +Use the helper script. It clones the published tag, builds inside an older base +image with g++-13 from the `ubuntu-toolchain-r` PPA, statically links libstdc++, +and writes the `.so` to `./native` (override with `OUT_DIR`): + +```bash +# single-objective, default Ubuntu 20.04 base, output into the examples project +OUT_DIR="$PWD/examples/native" scripts/build_brkga_native.sh + +# Other knobs (all optional env vars). This builds objective counts 1, 2 and 3, +# adds the generic bridge, and targets the oldest supported PPA base: +TUPLE_NS="1 2 3" \ +GENERIC=1 \ +IMAGE=ubuntu:18.04 \ + scripts/build_brkga_native.sh +``` + +Then either: + +- put the output in **`examples/native/`** (the default when you run the examples + from `examples/`): [`run.sh`](../../examples/run.sh) picks it up automatically, + no flags needed; **or** +- point your own app at it explicitly: + + ```bash + java --enable-native-access=ALL-UNNAMED -Dbrkga.bridge.dir=/path/to/native ... + ``` + + A file in `-Dbrkga.bridge.dir` wins over the same bundled file. If a requested + bridge is absent from that directory, the loader falls back to the JAR. + +### Route B — local build, no Docker (the most portable) + +Building on the old host itself links against exactly that host's glibc, which is +the surest match. You need g++ 13 + make + OpenMP on that host: + +```bash +git submodule update --init # fetch the upstream headers +make -C brkga_mp_ipr_java/native tuples TUPLE_NS="1" \ + CXX="g++-13 -static-libstdc++ -static-libgcc" +``` + +Copy the resulting `libbrkga_bridge_*.so` next to your working directory as +`native/…`, or point `-Dbrkga.bridge.dir` at them. + +### Notes + +- **Multiple objectives.** `TUPLE_NS="1"` only builds the single-objective + binary. For `Brkga.forObjectives(2)` or `(3)`, the loader would then fall back + to the corresponding binary bundled in the JAR, which still cannot load on + the older host. Build every count you need (`TUPLE_NS="1 2 3"`) or add + `GENERIC=1` for a runtime-selectable local binary. +- **Remaining runtime dependency.** The binaries still need OpenMP at run time + (`libgomp.so.1`, from the `libgomp1` package) — that is a small, universally + available shared library, not a GLIBCXX-versioned one. The script's final + `ldd` check reports any unresolved dependency. + +--- + ## Keeping extra data in the chromosome The `Chromosome` class can carry an inline *extra blob* — a few auxiliary diff --git a/examples/README.md b/examples/README.md index 5b9d6e7..c41414e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -73,3 +73,13 @@ the parallel-mating mode, or the extra-blob capacity, build your own binaries wi Docker (no local toolchain needed) and point the JVM at them with `-Dbrkga.bridge.dir=...`. See [JAVA_GUIDE.md → Recompiling the native library](https://github.com/codeurjc/brkga_mp_ipr_java/blob/main/brkga_mp_ipr_java/docs/JAVA_GUIDE.md#recompiling-the-native-library). + +**On an older Linux?** The bundled binaries need glibc ≥ 2.32 and a libstdc++ +exporting GLIBCXX_3.4.32 or newer. On a system with older versions the example +aborts with +`Exception Occurred: Cannot open library: /tmp/brkga-native-*/libbrkga_bridge_1.so` +(the real reason is the too-new `GLIBC_2.32` / `GLIBCXX_3.4.32`). Build a +compatible bridge into `examples/native/` — which `run.sh` then picks up +automatically — with +[`scripts/build_brkga_native.sh`](https://github.com/codeurjc/brkga_mp_ipr_java/blob/main/scripts/build_brkga_native.sh); +see [JAVA_GUIDE.md → Running on an older Linux](https://github.com/codeurjc/brkga_mp_ipr_java/blob/main/brkga_mp_ipr_java/docs/JAVA_GUIDE.md#running-on-an-older-linux-glibc--glibcxx-too-new). diff --git a/scripts/build_brkga_native.sh b/scripts/build_brkga_native.sh new file mode 100755 index 0000000..2a5f717 --- /dev/null +++ b/scripts/build_brkga_native.sh @@ -0,0 +1,186 @@ +#!/usr/bin/env bash +############################################################################### +# build_brkga_native.sh: build the BRKGA native bridge so it runs on THIS host. +# +# Why this exists: brkga-mp-ipr-java bundles prebuilt libbrkga_bridge_*.so, but +# they are compiled on Ubuntu 24.04 and need GLIBC_2.32 + GLIBCXX_3.4.32. Hosts +# older than that (Ubuntu 20.04 ships glibc 2.31 / GLIBCXX 3.4.28) fail to load +# them with "Cannot open library: /tmp/brkga-native-*/libbrkga_bridge_1.so". +# +# The build runs inside an older base image ($IMAGE, default ubuntu:20.04) so the +# result links against that image's (older) glibc, and it statically links +# libstdc++/libgcc so it does not need a newer GLIBCXX either. Docker is used +# once, here; afterwards the BRKGA runs natively. +# +# The bridge needs a real C++20 library (, and operator<< for +# std::chrono::duration), so g++-13 from the ubuntu-toolchain-r PPA is used: the +# distro's g++-9 has no and g++-10's libstdc++ lacks the chrono +# inserters. The PPA covers Ubuntu LTS (18.04/20.04/22.04); to target a +# non-Ubuntu / non-Docker host, build directly with `make` on that host instead +# (see JAVA_GUIDE.md "Running on an older Linux"). +# +# Output: $OUT_DIR/libbrkga_bridge_*.so (default ./native). The library picks up +# a "native" directory relative to the JVM working directory automatically, so +# running the examples from examples/ finds examples/native/... with no flags; +# for any other layout point the JVM at it with -Dbrkga.bridge.dir=$OUT_DIR. +# +# The temporary clone is removed on exit. Set KEEP_WORK_DIR=1 to retain it for +# debugging; its path is printed as soon as it is created. +# +# Usage (all knobs are optional environment variables): +# scripts/build_brkga_native.sh +# +# BRKGA_TAG git tag to clone (keep in sync with the version you use) [v0.2.0] +# IMAGE older base image to build in [ubuntu:20.04] +# TUPLE_NS objective counts to build, space-separated [1] +# e.g. TUPLE_NS="1 2 3" for the single + two/three-objective demos +# GENERIC set to 1 to also build libbrkga_bridge_generic.so [0] +# EXTRA_CAP inline extra-blob capacity (doubles), uniform across binaries [8] +# CAP ABI capacity; only 20 is accepted (must match Java 0.2.0) [20] +# MATING mating mode (MATING_SEQUENTIAL|MATING_SEED_ONLY|MATING_FULL_SPEED) +# [MATING_SEQUENTIAL] +# OUT_DIR where the .so files are written [$PWD/native] +# KEEP_WORK_DIR set to 1 to retain the temporary clone [0] +# +# Example: build single + two-objective on an Ubuntu 18.04 base, into the +# examples project so ./run.sh finds them automatically: +# TUPLE_NS="1 2" IMAGE=ubuntu:18.04 OUT_DIR="$PWD/examples/native" \ +# scripts/build_brkga_native.sh +############################################################################### +set -euo pipefail + +# Keep BRKGA_TAG in sync with the artifact version you depend on. +BRKGA_TAG="${BRKGA_TAG:-v0.2.0}" +IMAGE="${IMAGE:-ubuntu:20.04}" +TUPLE_NS="${TUPLE_NS:-1}" +GENERIC="${GENERIC:-0}" +EXTRA_CAP="${EXTRA_CAP:-8}" +CAP="${CAP:-20}" +MATING="${MATING:-MATING_SEQUENTIAL}" +OUT_DIR="${OUT_DIR:-$PWD/native}" +KEEP_WORK_DIR="${KEEP_WORK_DIR:-0}" + +# Validate everything that is interpolated into the Make invocation before any +# network access or Docker work. CAP is part of BridgeStatus's binary layout and +# therefore must match AlgorithmStatus.CAP in the published Java artifact. +if [ "${CAP}" != "20" ]; then + echo "CAP=${CAP} is incompatible with the Java 0.2.0 ABI; only CAP=20 is supported." >&2 + echo "Changing CAP requires rebuilding the Java wrapper and AlgorithmStatus layout too." >&2 + exit 2 +fi +case "${GENERIC}" in + 0|1) ;; + *) echo "GENERIC must be 0 or 1 (got '${GENERIC}')." >&2; exit 2 ;; +esac +case "${KEEP_WORK_DIR}" in + 0|1) ;; + *) echo "KEEP_WORK_DIR must be 0 or 1 (got '${KEEP_WORK_DIR}')." >&2; exit 2 ;; +esac +case "${EXTRA_CAP}" in + ''|*[!0-9]*|0) echo "EXTRA_CAP must be a positive integer (got '${EXTRA_CAP}')." >&2; exit 2 ;; +esac +case "${MATING}" in + MATING_SEQUENTIAL|MATING_SEED_ONLY|MATING_FULL_SPEED) ;; + *) echo "Invalid MATING mode: '${MATING}'." >&2; exit 2 ;; +esac +read -r -a tuple_values <<< "${TUPLE_NS}" +if [ "${#tuple_values[@]}" -eq 0 ]; then + echo "TUPLE_NS must contain at least one objective count." >&2 + exit 2 +fi +for n in "${tuple_values[@]}"; do + case "${n}" in + ''|*[!0-9]*) echo "TUPLE_NS contains a non-integer value: '${n}'." >&2; exit 2 ;; + esac + if [ "${n}" -lt 1 ] || [ "${n}" -gt 20 ]; then + echo "TUPLE_NS objective counts must be between 1 and 20 (got '${n}')." >&2 + exit 2 + fi +done +for required_command in git docker readelf ldd; do + if ! command -v "${required_command}" >/dev/null 2>&1; then + echo "Required command not found: ${required_command}" >&2 + exit 2 + fi +done + +WORK_DIR="$(mktemp -d)" +echo "==> Temporary build tree: ${WORK_DIR}" + +cleanup() { + rc=$? + trap - EXIT + if [ "${KEEP_WORK_DIR}" = "1" ]; then + echo "==> Build tree retained at ${WORK_DIR}" + elif ! rm -rf -- "${WORK_DIR}"; then + echo "!!! Could not completely remove ${WORK_DIR}; remove it manually." >&2 + fi + exit "${rc}" +} +trap cleanup EXIT + +echo "==> Cloning brkga_mp_ipr_java ${BRKGA_TAG}" +git clone -q --depth 1 --branch "${BRKGA_TAG}" \ + --recurse-submodules --shallow-submodules \ + https://github.com/codeurjc/brkga_mp_ipr_java.git "${WORK_DIR}/src" + +echo "==> Building bridges in ${IMAGE} (g++-13, static libstdc++)" +echo " TUPLE_NS='${TUPLE_NS}' GENERIC=${GENERIC} MATING=${MATING}" \ + "EXTRA_CAP=${EXTRA_CAP} CAP=${CAP}" +docker run --rm --user root \ + -v "${WORK_DIR}/src":/src -w /src/brkga_mp_ipr_java/native \ + -e TUPLE_NS="${TUPLE_NS}" -e GENERIC="${GENERIC}" -e MATING="${MATING}" \ + -e EXTRA_CAP="${EXTRA_CAP}" -e CAP="${CAP}" \ + -e HOST_UID="$(id -u)" -e HOST_GID="$(id -g)" \ + "${IMAGE}" bash -c ' + set -euo pipefail + fix_ownership() { + chown -R "${HOST_UID}:${HOST_GID}" build libbrkga_bridge_*.so 2>/dev/null || true + } + trap fix_ownership EXIT + export DEBIAN_FRONTEND=noninteractive + apt-get update -qq + apt-get install -y -qq software-properties-common + add-apt-repository -y ppa:ubuntu-toolchain-r/test + apt-get update -qq + apt-get install -y -qq g++-13 make + # Statically link libstdc++/libgcc by folding the flags into CXX (the + # Makefile invokes "$(CXX) $(CXXFLAGS) ... -shared"). This works against + # any released Makefile and keeps its tuned optimization flags, so the + # .so carries its own C++ runtime and needs no host GLIBCXX. + CXX_STATIC="g++-13 -static-libstdc++ -static-libgcc" + make tuples TUPLE_NS="${TUPLE_NS}" CXX="${CXX_STATIC}" MATING="${MATING}" EXTRA_CAP="${EXTRA_CAP}" CAP="${CAP}" + if [ "${GENERIC}" = "1" ]; then + make generic CXX="${CXX_STATIC}" MATING="${MATING}" EXTRA_CAP="${EXTRA_CAP}" CAP="${CAP}" + fi + ' >/dev/null + +# Stage the fresh build before touching OUT_DIR. Then replace the complete set of +# generated bridge files so stale variants from an earlier run cannot be loaded. +STAGE_DIR="${WORK_DIR}/stage" +mkdir -p "${STAGE_DIR}" +cp "${WORK_DIR}"/src/brkga_mp_ipr_java/native/libbrkga_bridge_*.so "${STAGE_DIR}/" +mkdir -p "${OUT_DIR}" +find "${OUT_DIR}" -maxdepth 1 ! -type d -name 'libbrkga_bridge_*.so' -delete +cp "${STAGE_DIR}"/libbrkga_bridge_*.so "${OUT_DIR}/" + +echo "==> Wrote:" +for so in "${OUT_DIR}"/libbrkga_bridge_*.so; do echo " ${so}"; done + +status=0 +for so in "${OUT_DIR}"/libbrkga_bridge_*.so; do + if readelf -d "${so}" 2>/dev/null | grep -Fq 'Shared library: [libstdc++.so.6]'; then + echo "!!! ${so} still depends directly on libstdc++.so.6; static linking failed." >&2 + status=1 + fi + if ldd "${so}" 2>&1 | grep -q 'not found'; then + echo "!!! Unresolved dependencies for ${so} on this host:" + ldd "${so}" 2>&1 | grep 'not found' + status=1 + fi +done +if [ "${status}" -ne 0 ]; then + echo "!!! libgomp.so.1 comes from the libgomp1 package (OpenMP runtime)." + exit 1 +fi +echo "==> All dependencies resolve on this host. BRKGA can now run without Docker."