Skip to content

fix: BuildFedora.sh actually builds on Fedora (dnf, CMake 4.x, system-lib ABI mismatches) - #229

Open
bugparty wants to merge 8 commits into
QIDITECH:mainfrom
bugparty:fix/build-fedora-sh-apt-dnf
Open

fix: BuildFedora.sh actually builds on Fedora (dnf, CMake 4.x, system-lib ABI mismatches)#229
bugparty wants to merge 8 commits into
QIDITECH:mainfrom
bugparty:fix/build-fedora-sh-apt-dnf

Conversation

@bugparty

@bugparty bugparty commented Sep 4, 2026

Copy link
Copy Markdown

Summary

BuildFedora.sh was a copy of the Debian/Ubuntu build script that never got ported to Fedora. Beyond the surface-level apt->dnf and BuildLinux.sh->BuildFedora.sh issues, the -d (deps) and -s (app) steps didn't actually produce a working build on Fedora 44 / CMake 4.x. This PR was verified end-to-end multiple times with a full clean sudo ./BuildFedora.sh -u -> ./BuildFedora.sh -d -> ./BuildFedora.sh -b -s run.

  • apt -> dnf: the -u dependency-install step called apt with Debian package names; switched to dnf with Fedora package names.
  • CMake 4.x compatibility: deps/CMakeLists.txt required CMake >= 3.2, and CMake 4.x refuses to configure anything below 3.5 at all. Bumped it, and pass CMAKE_POLICY_VERSION_MINIMUM=3.5 (both as a cmake arg and an env var, so it also covers bundled deps' own nested try_compile() checks) to work around the same problem in third-party vendored CMakeLists.txt files (NLopt, wxWidgets, etc.) that can't be edited directly.
  • GLEW/OpenVDB static linking: Fedora's glew-devel/openvdb-devel ship only shared .so libs, no static .a, but SLIC3R_STATIC forces static linking of both. Added SLIC3R_STATIC_EXCLUDE_OPENVDB (mirroring the existing SLIC3R_STATIC_EXCLUDE_GLEW) and pass both from BuildFedora.sh.
  • Shared destdir header pollution: deps/ unconditionally built its own GLFW, OpenVDB (+OpenEXR/Imath) and expat even when a usable system version exists. Since all deps share one install prefix/include root, those headers silently shadow Fedora's system headers regardless of any CMake variable override — causing ABI-mismatched undefined-symbol link errors (GLFW needs KDE's extra-cmake-modules for its Wayland backend; OpenVDB's ABI-versioned inline namespaces don't match Fedora's; webkit2gtk needs a matching dynamic libexpat.so, not deps' static one). Added DEP_BUILD_OPENVDB/DEP_BUILD_EXPAT toggles (mirroring the existing DEP_BUILD_GLFW) and disabled all three from BuildFedora.sh.
  • wx-config lib64 mismatch: wx-config hardcodes -L.../lib for its own deps (e.g. -lzlibstatic), but zlib's own CMakeLists follows GNUInstallDirs, which resolves to lib64 on Fedora. Added lib64 to the linker search path.
  • Conda/miniforge PATH contamination: if a conda environment is active (common default shell setup), its bin/ sits ahead of the system toolchain on PATH, and CMake's find_package(... CONFIG) treats PATH entries as candidate install prefixes. This silently resolved zstd (pulled in transitively by Boost::iostreams) to conda's older copy instead of Fedora's libzstd-devel, and CMake baked that path into the built binary's RPATH — which then also shadowed the system libexpat.so at runtime via the same RPATH entry, regardless of whether conda was active when actually running the binary. Strip $CONDA_PREFIX from PATH at the top of the script.
  • New required packages: added nasm, boost-static, webkit2gtk4.1-devel, mesa-compat-libOSMesa-devel, openvdb-devel, imath-devel, openexr-devel, NLopt-devel, glfw-devel to the -u dependency list. (Note: Fedora's cereal-devel is deliberately not installed — it exports a namespaced cereal::cereal target that doesn't match this codebase's target_link_libraries(... cereal) calls, unlike the bare cereal target the bundled deps build exports.)
  • Parallelism: the -s step's final make -j4 QIDIStudio was hardcoded regardless of core count; changed to $NCORES to match the -d step.

Test plan

  • sudo ./BuildFedora.sh -u installs cleanly on Fedora 44
  • ./BuildFedora.sh -d builds all dependencies from a clean deps/build
  • ./BuildFedora.sh -b -s builds qidi-studio from a clean build, end to end, no manual intervention (verified twice)
  • Resulting qidi-studio binary launches and runs the GUI

https://claude.ai/code/session_01GX1HqJrRdEWvoiwXkfrLQH

@bugparty bugparty changed the title fix: BuildFedora.sh uses apt/BuildLinux.sh instead of dnf/BuildFedora.sh fix: BuildFedora.sh actually builds on Fedora (dnf, CMake 4.x, system-lib ABI mismatches) Sep 6, 2026
….sh usage text

BuildFedora.sh was a copy of the Debian/Ubuntu build script that never
got ported: the -u dependency-install block still called apt with
Debian package names, and the usage/help text still referenced
BuildLinux.sh. Switched the dependency installation to dnf with the
Fedora equivalent package names, and corrected the usage strings to
reference BuildFedora.sh.

Claude-Session: https://claude.ai/code/session_01GX1HqJrRdEWvoiwXkfrLQH
Beyond the apt->dnf and BuildLinux.sh->BuildFedora.sh renames, the deps
build (-d) and app build (-s) steps didn't actually work on Fedora
44/CMake 4.x. Fixes, verified with a full clean `-u` -> `-d` -> `-b -s`
run:

- deps/CMakeLists.txt required CMake >= 3.2, and CMake 4.x refuses to
  configure anything below 3.5 at all. Bumped it, and pass
  CMAKE_POLICY_VERSION_MINIMUM=3.5 (as both a cmake arg and an env var,
  so it also applies to bundled deps' own nested try_compile() checks)
  to work around the same problem in third-party vendored CMakeLists.txt
  files (NLopt, wxWidgets, etc.) we can't edit directly.

- Fedora's glew-devel and openvdb-devel ship only shared .so libs, no
  static .a, but SLIC3R_STATIC forces static linking of both. Added
  SLIC3R_STATIC_EXCLUDE_OPENVDB (mirroring the existing
  SLIC3R_STATIC_EXCLUDE_GLEW) and pass both from BuildFedora.sh so the
  app links the system shared libs instead.

- deps/ unconditionally built its own GLFW, OpenVDB (+OpenEXR/Imath) and
  expat even when a usable system version exists, and being under the
  same shared destdir/include root as everything else, those headers
  silently shadow Fedora's system headers regardless of any CMake
  variable override -- causing ABI-mismatched undefined-symbol link
  errors (GLFW needs KDE's extra-cmake-modules for its Wayland backend;
  OpenVDB's ABI-versioned inline namespaces don't match Fedora's; and
  webkit2gtk needs a matching dynamic libexpat.so, not deps' static
  one). Added DEP_BUILD_OPENVDB/DEP_BUILD_EXPAT toggles (mirroring the
  existing DEP_BUILD_GLFW) and disabled all three from BuildFedora.sh.

- wx-config hardcodes "-L.../lib" for its own deps (e.g.
  "-lzlibstatic"), but zlib's own CMakeLists follows GNUInstallDirs,
  which resolves to "lib64" on Fedora. Added lib64 to the linker search
  path.

- Added the now-required Fedora devel packages to the -u dependency
  list: nasm, boost-static, webkit2gtk4.1-devel,
  mesa-compat-libOSMesa-devel, openvdb-devel, imath-devel,
  openexr-devel, NLopt-devel, glfw-devel.

- The -s step's final `make -j4 QIDIStudio` was hardcoded regardless of
  core count; changed to $NCORES to match the -d step.

Claude-Session: https://claude.ai/code/session_01GX1HqJrRdEWvoiwXkfrLQH
If a conda/miniforge environment is active (very common as a default
shell setup), its bin/ directory sits ahead of the system toolchain on
PATH. CMake's find_package(... CONFIG) search treats PATH entries as
candidate install prefixes, so it can silently resolve a dependency
(observed with zstd, pulled in transitively by Boost::iostreams) to an
older/incompatible copy from the conda env instead of Fedora's own
libzstd-devel -- and since CMake auto-adds found libraries' directories
to the built binary's RPATH, that conda path gets baked into
qidi-studio itself. This made the binary pick up conda's outdated
libexpat.so.1 too (shared indirectly via the same RPATH entry) at
runtime, regardless of the invoking shell's LD_LIBRARY_PATH or whether
conda was still active when actually running the binary.

Strip $CONDA_PREFIX from PATH at the top of the script so the Fedora
system toolchain and libraries are used consistently throughout
configure and build. Verified with another full clean -u/-d/-b -s run:
the resulting binary's RUNPATH no longer references the conda
environment.

Claude-Session: https://claude.ai/code/session_01GX1HqJrRdEWvoiwXkfrLQH
@bugparty
bugparty force-pushed the fix/build-fedora-sh-apt-dnf branch from 1f6bdad to 6cacd92 Compare September 6, 2026 06:40
Assimp's contrib/zlib is an old vendored fork whose zutil.h still has
the classic `#if defined(MACOS) || defined(TARGET_OS_MAC)` branch that
redefines fdopen() to NULL. TARGET_OS_MAC is unconditionally 1 on all
Apple platforms (not just legacy Mac OS Classic, which this guard was
written for), so on macOS-15/Xcode 16 this macro corrupts the system
_stdio.h's fdopen() declaration and fails the CI build with "error:
expected identifier or '('".

Assimp.cmake was passing -DASSIMP_BUILD_ZLIB=ON, forcing it to compile
this broken vendored copy instead of the project's own already-fixed
zlib (deps/ZLIB/ZLIB.cmake). Every other dependency that needs zlib
(CURL, PNG, TIFF, wxWidgets, OpenEXR, Blosc, JPEG) already depends on
${ZLIB_PKG} and lets find_package(ZLIB) resolve it via the shared
CMAKE_PREFIX_PATH; Assimp was the one outlier still building its own.
Turned ASSIMP_BUILD_ZLIB off and added the same DEPENDS so Assimp
finds the shared zlib instead.

Claude-Session: https://claude.ai/code/session_013GV54EAeMeXrZuiGg6X2Ct
FFMPEG.cmake built its own `make ${_build_j}` invocation with
`_build_j` defaulting to a bare `-j` (unlimited parallel jobs) unless
CMAKE_BUILD_PARALLEL_LEVEL happened to be set in the environment. On
the macOS-15 GitHub Actions runner this exhausted the process table
mid-build ("/bin/sh: fork: Resource temporarily unavailable", "make:
*** [fftools/ffmpeg_demux.o] Error 128").

The rest of deps/CMakeLists.txt already computes a bounded NPROC
(ProcessorCount, overridable via CMAKE_BUILD_PARALLEL_LEVEL) and uses
it for every other dependency's build step. FFMPEG.cmake was
reimplementing the same env-var check on its own, but without the
ProcessorCount fallback, so its effective default parallelism was
unbounded. Reuse NPROC directly instead of duplicating the logic.

Claude-Session: https://claude.ai/code/session_013GV54EAeMeXrZuiGg6X2Ct
…UBLIC

CI builds with -DQDT_RELEASE_TO_PUBLIC=0 (the proprietary QIDI/ cloud
sync sources aren't in this checkout), but src/slic3r/CMakeLists.txt
still listed QIDI/UserPresetSyncManager.cpp/.hpp unconditionally in
SLIC3R_GUI_SOURCES, so add_library() failed with "Cannot find source
file" once the deps build got far enough to reach the app's CMake
configure step.

Every actual use of UserPresetSyncManager in GUI_App.cpp/.hpp is
already wrapped in #if QDT_RELEASE_TO_PUBLIC -- only the CMakeLists
source list was unguarded. Upstream hit and fixed this exact issue in
911a3ea ("fix: build without QIDI proprietary assets"), which moved
these two files into the existing `if(QDT_RELEASE_TO_PUBLIC)` guarded
list alongside QIDINetwork.cpp/P2PManager.cpp. This branch predates
that commit, so port just the src/slic3r/CMakeLists.txt hunk (the
resulting file is byte-identical to upstream's fixed version).

Claude-Session: https://claude.ai/code/session_013GV54EAeMeXrZuiGg6X2Ct
The Linux CI step tries to force QDT_RELEASE_TO_PUBLIC=0 by sed-patching
BuildLinux.sh for the literal string "-DQDT_INTERNAL_TESTING=0", but
BuildLinux.sh only ever writes that flag as -DQDT_INTERNAL_TESTING=${INTERNAL_TESTING}
(a variable, never the literal "0"), so the sed is a silent no-op and
QDT_RELEASE_TO_PUBLIC keeps its "1" default. CMake then configures the
QDT_RELEASE_TO_PUBLIC-guarded proprietary QIDI/ sources (QIDINetwork.cpp,
P2PManager.cpp, etc.), none of which exist in this checkout, and
add_library() fails with "Cannot find source file".

Upstream hit the same class of bug and fixed it in 911a3ea ("fix:
build without QIDI proprietary assets") by making version.inc
auto-detect missing QIDI/ sources and force QDT_RELEASE_TO_PUBLIC off
regardless of what was passed in, instead of relying on every build
script/CI step to thread the flag through correctly. Port that same
version.inc fallback here so all three CI platforms build correctly
even when their flag-passing is unreliable.
The macOS CI step brew-installs boost and injects it into
CMAKE_PREFIX_PATH ahead of the project's own destdir
($DEPS/usr/local): "-DCMAKE_PREFIX_PATH=\"$CMAKE_PREFIX_PATH;$DEPS...".
find_package(Boost) in CONFIG mode picks the first root satisfying the
minimum version, so it resolved to Homebrew's Boost 1.92.0 instead of
the project's own pinned Boost 1.84.0 (built from source by
deps/Boost/Boost.cmake specifically so the app isn't at the mercy of
whatever boost version the CI image happens to have). Something about
that newer Boost's ABI doesn't match what libslic3r/libslic3r_gui was
compiled against, and the final link fails with undefined symbols for
several boost::filesystem::detail:: functions.

BuildMac.sh's own default is "-DCMAKE_PREFIX_PATH=\"$DEPS/usr/local\""
(no Homebrew paths at all), so put $DEPS/usr/local back in front and
keep the brew-installed libs only as a fallback after it, instead of
ahead of it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant