Homebrew prefix transition from /usr/local to /opt/homebrew breaks CI build scripts
0 reputation · 07 Sept 2022, 23:31 UTC
0 reputation · 07 Sept 2022, 23:31 UTC
Homebrew changed its default installation prefix when Apple Silicon was introduced, moving from /usr/local to /opt/homebrew. Build scripts and application configurations that hardcode the legacy Intel path continue to work on older machines but fail when the same repository is built on an arm64 CI runner. The documented brew shellenv command is intended to initialize PATH and MANPATH so the correct prefix is prioritized, yet it does not rewrite absolute paths embedded in Makefiles, shell scripts, or generated configuration files.
The goal is to maintain a single source repository that builds identically on both Intel and Apple Silicon machines without maintaining duplicate pipeline definitions. One constraint is that Rosetta 2 permits an Intel Homebrew instance under /usr/local/Homebrew on an arm64 system, so the presence of a /usr/local directory does not reliably indicate architecture. Another constraint is that mixing Intel and ARM binaries in the same PATH can produce unpredictable linkage errors, making it unsafe to simply prepend both prefixes.
Should the project standardize on dynamic prefix resolution using brew --prefix in all build tooling, or should CI runners be pinned to the same architecture as the development machines to avoid prefix mismatches entirely?
Is there a documented compatibility boundary that determines when brew shellenv is sufficient versus when explicit prefix substitution is required, and what is the recommended verification procedure to confirm that the correct Cellar symlinks are being resolved before a production build?
33775 reputation · 08 Sept 2022, 02:33 UTC
Standardize on dynamic prefix resolution using brew --prefix (or the $HOMEBREW_PREFIX environment variable) in every build step that references Homebrew‑installed files. Pinning CI runners to a single architecture is not required and reduces cross‑architecture testing.
brew shellenv only adjusts PATH and MANPATH; it does not rewrite absolute paths that are hard‑coded in Makefiles, shell scripts, or generated configuration files. Those hard‑coded references to /usr/local continue to fail on arm64 runners where Homebrew lives under /opt/homebrew. By substituting the prefix at build time, the same source tree resolves to the correct Cellar location on both Intel and Apple Silicon machines.
/usr/local/bin, /usr/local/include, /usr/local/lib).brew --prefix. In Makefiles you can use:HOMEBREW_PREFIX := $(shell brew --prefix)
CFLAGS += -I$(HOMEBREW_PREFIX)/include
LDFLAGS += -L$(HOMEBREW_PREFIX)/lib
export HOMEBREW_PREFIX=$(brew --prefix)
"$HOMEBREW_PREFIX/bin/foo" --option
pkg-config, ensure it queries the correct prefix by setting PKG_CONFIG_PATH:export PKG_CONFIG_PATH="$HOMEBREW_PREFIX/lib/pkgconfig:$HOMEBREW_PREFIX/share/pkgconfig"
brew --prefix in both the developer environment and the CI runner; the output must match the expected architecture‑specific prefix (/usr/local for Intel, /opt/homebrew for Apple Silicon).echo "Resolved libfoo path: $(brew --prefix)/Cellar/libfoo/*/lib/libfoo.dylib"
brew --prefix and that the binary’s architecture matches the runner (use file or lipo -info).brew --prefix does not equal the expected value for the runner’s architecture.brew shellenv alone is sufficientIf a build step only invokes Homebrew‑installed binaries via PATH (no absolute paths), brew shellenv is enough. Any step that resolves a Cellar symlink, includes headers, or links libraries requires explicit prefix substitution.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.