# o3de-dxc-spirv — license-clean Linux DXC build for O3DE # # Builds the DirectX Shader Compiler (DXC) from O3DE's fork at # release-1.8.2505.1-o3de, configured Linux/SPIR-V-only — no Windows # DXIL signing tooling. Per Nick_L (sig-build, 2026-05-05): the engine # doesn't link DXC at all, just shells out to the dxc binary, so the # rebuild only needs to produce a working dxc executable. # # License: NCSA + Apache-2.0 (with LLVM exception). Both Fedora- # compatible; no proprietary signing tools included. # # Cmake flags below mirror what o3de/3p-package-source's # package-system/DirectXShaderCompiler/build_config.json sets for # Linux. Source git_tag matches the most recent published bundle. # # This is the "PoC" stage — proves the rebuild is buildable as a # Fedora-style RPM. Packaging hardening (multi-arch, hermetic builds, # unit-test gating, debuginfo split, etc.) is follow-on work. Goal of # this iteration: get a green local build + a binary RPM that produces # a functioning dxc executable. %global o3de_dxc_commit release-1.8.2505.1-o3de %global o3de_dxc_pkgrev rev13 # DirectX-Headers submodule SHA matching DXC's pin at release-1.8.2505.1-o3de # (verified via `gh api /repos/o3de/DirectXShaderCompiler/git/trees/...:external`). # Commit date: 2022-01-31 (Walbourn merge PR #47). %global dxh_commit 980971e835876dc0cde415e8f9bc646e64667bf7 %global dxh_short %(c=%{dxh_commit}; echo ${c:0:7}) Name: o3de2605-dxc-spirv Version: 1.8.2505.1 Release: 1.%{o3de_dxc_pkgrev}%{?dist} Summary: DirectX Shader Compiler (Linux/SPIR-V-only build) for Open 3D Engine 26.05 License: NCSA AND Apache-2.0 WITH LLVM-exception URL: https://github.com/o3de/DirectXShaderCompiler # Versioned-major rename: see o3de-rpm memory note # `project_o3de_3p_versioning_research.md` for empirical research that # motivated the o3deNNNN- naming convention. Obsoletes/Provides keep # `dnf upgrade` seamless from the unversioned o3de-dxc-spirv (rev1-rev12). Obsoletes: o3de-dxc-spirv < 1.8.2505.1-1.rev13 Provides: o3de-dxc-spirv = %{version}-%{release} # Source: tarball generated from o3de/DirectXShaderCompiler at # tag release-1.8.2505.1-o3de. We don't fetch directly via git in # %prep because COPR builders run with enable_net=false for license- # clean repos; pre-staged tarball is the canonical input. # # Note: the tarball is created via plain `git archive` (non-recursive), # so the three external/* git submodules (DirectX-Headers, SPIRV-Headers, # SPIRV-Tools) end up as empty directories. Patch0001 below adds a # system-package fallback to DXC's external/CMakeLists.txt so the build # uses Fedora's spirv-headers-devel, spirv-tools-devel, and DirectX- # Headers-devel instead of the missing submodule sources. Source0: DirectXShaderCompiler-%{o3de_dxc_commit}.tar.gz # DirectX-Headers source at DXC's pinned submodule SHA (license: MIT, Microsoft). # DXC's external/CMakeLists.txt expects external/DirectX-Headers/include/{d3d12,...}.h # — the SAME layout this tarball provides — so DXC's existing IS_DIRECTORY + # add_subdirectory branch builds it normally, no Patch0001-style fallback needed. # This was switched in rev10 from Fedora's DirectX-Headers-devel because Fedora's # wsl/stubs/basetsd.h has typedef conflicts with DXC's own include/dxc/WinAdapter.h # (Fedora: typedef int32_t LONG, DXC: typedef long LONG — incompatible at LP64). Source2: DirectX-Headers-%{dxh_short}.tar.gz # Patch the empty-submodule fallback path in external/CMakeLists.txt: # - SPIRV-Headers: find_package(SPIRV-Headers) + set SPIRV-Headers_SOURCE_DIR # to /usr (so DXC's existing `${SPIRV-Headers_SOURCE_DIR}/include` resolves # to /usr/include where Fedora ships spirv/unified1/spirv.hpp etc). # - SPIRV-Tools: find_package(SPIRV-Tools) + find_package(SPIRV-Tools-opt). # Fedora ships `SPIRV-Tools` as SHARED IMPORTED via SPIRV-ToolsConfig.cmake; # `SPIRV-Tools-opt` via SPIRV-Tools-optConfig.cmake. Both are needed by DXC's # downstream link targets (dxc, dxclib, clangSPIRV). # - SPIRV_DEP_TARGETS loop: wrap set_property(TARGET SPIRV-Tools-static ...) in # `if (TARGET ...)` because Fedora doesn't ship a static SPIRV-Tools target. # DirectX-Headers is handled differently — Fedora ships no cmake config, so we # pass `-DDIRECTX_HEADER_INCLUDE_DIR=/usr/include/directx` in %build to bypass # DXC's DirectX-Headers-submodule lookup entirely. Patch0001: 0001-external-cmake-system-spirv-fallback.patch # Add SPIRV-Tools (the main library) alongside SPIRV-Tools-opt in # clangSPIRV's LINK_LIBS list. Required because Fedora's imported # `SPIRV-Tools-opt` target doesn't establish the transitive # INTERFACE_LINK_LIBRARIES → SPIRV-Tools that bundled SPIRV-Tools # provides natively. clangSPIRV is the actual consumer of the spv* # C-API symbols (SpirvTools class, spvOptimizerOptions*, # spvValidatorOptions*, etc. — all in libSPIRV-Tools.so), so listing # it explicitly is more reliable than trying to graft a transitive # edge onto an IMPORTED target (rev11 attempted that in Patch0001 and # the link-line propagation didn't work). Patch0002: 0002-clangSPIRV-add-SPIRV-Tools-to-link-libs.patch BuildRequires: cmake BuildRequires: ninja-build BuildRequires: gcc-c++ BuildRequires: python3 # DXC's `utils/version/CMakeLists.txt` runs `git rev-parse HEAD` to embed # a commit hash into `dxcversion.inc`. Required at build time even though # the resulting binary doesn't link git. BuildRequires: git # DXC is a Clang/LLVM fork — the upstream sources include their own # embedded LLVM tree, no system-LLVM linkage required at build time. # System SPIR-V dependencies — Patch0001 redirects DXC's submodule lookups # to these Fedora packages. BuildRequires: spirv-headers-devel BuildRequires: spirv-tools-devel # Note: DirectX-Headers is NOT a BR — we ship the bundled DirectX-Headers # sources via Source2 instead, due to typedef conflicts between Fedora's # `/usr/include/wsl/stubs/basetsd.h` and DXC's `include/dxc/WinAdapter.h` # (`LONG = int32_t` vs `long`). See rev10 changelog for full diagnosis. %description DirectX Shader Compiler (DXC) — Microsoft's HLSL→SPIR-V/DXIL compiler, forked by Open 3D Engine to add Linux build fixes and the dxsc helper tool. This build is Linux/SPIR-V-only (no DXIL signing tooling) so the resulting binaries are redistributable under NCSA + Apache-2.0 (with LLVM exception). Used by O3DE's shader pipeline as an external invocation: the engine shells out to dxc to compile HLSL shaders to SPIR-V at asset-build time. This package replaces the bundled DXC tarball O3DE fetches from packages.o3de.org by default — providing a Fedora-shippable license- clean substitute for distros that can't redistribute the bundled upstream tarball (which includes proprietary Windows DXIL signing tooling that's not used on Linux but ships in the same archive). %prep # -p1 applies Patch0001 (system-spirv fallback for external/CMakeLists.txt). %autosetup -n DirectXShaderCompiler-%{o3de_dxc_commit} -p1 # DXC's external/CMakeLists.txt tests `IS_DIRECTORY ${DXC_SPIRV_HEADERS_DIR}` # before deciding whether to add_subdirectory the submodule or fall back to # Patch0001's system find_package path. Our `git archive`-generated tarball # leaves submodule directories present-but-empty, which makes IS_DIRECTORY # return TRUE — so cmake takes the add_subdirectory branch and fails with # "does not contain a CMakeLists.txt file" before reaching the Patch0001 # else()-branch. # # For SPIRV-Headers + SPIRV-Tools: rmdir the empty placeholders so the test # fails and Patch0001's system-package fallback fires. # For DirectX-Headers: extract Source2 (the DXC-pinned submodule SHA) into # the placeholder dir, so DXC's existing add_subdirectory branch builds the # bundled DirectX-Headers normally. rmdir external/SPIRV-Headers external/SPIRV-Tools 2>/dev/null || : rmdir external/DirectX-Headers 2>/dev/null || : mkdir -p external/DirectX-Headers tar -xzf %{SOURCE2} -C external/DirectX-Headers --strip-components=1 %build # Cmake flags mirror o3de/3p-package-source/.../build_config.json's # Linux build_configs, with three notable choices: # # - LLVM_TARGETS_TO_BUILD=None: no LLVM target backends. DXC's HLSL # frontend produces SPIR-V via its own pipeline; no Windows-DXIL, # no x86 native, no other LLVM target needed for the o3de use case. # - ENABLE_SPIRV_CODEGEN=ON: enable the SPIR-V codegen path (the # thing the engine actually uses). # - LIBCLANG_BUILD_STATIC=ON: build the embedded libclang as a static # library, so the shipped libdxcompiler.so is self-contained and # doesn't bleed an internal libclang-12.so.* runtime requirement # onto the system. (This was the source of the bundled DXC's # %__requires_exclude pain on the o3de spec side.) %cmake \ -GNinja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON \ -DBUILD_SHARED_LIBS:BOOL=OFF \ -DLLVM_APPEND_VC_REV:BOOL=ON \ -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=dxil-ms-dx \ -DLLVM_ENABLE_EH:BOOL=ON \ -DLLVM_ENABLE_RTTI:BOOL=ON \ -DLLVM_INCLUDE_DOCS:BOOL=OFF \ -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \ -DLLVM_INCLUDE_TESTS:BOOL=OFF \ -DLLVM_OPTIMIZED_TABLEGEN:BOOL=OFF \ -DLLVM_REQUIRES_EH:BOOL=ON \ -DLLVM_REQUIRES_RTTI:BOOL=ON \ -DLLVM_TARGETS_TO_BUILD:STRING=None \ -DLIBCLANG_BUILD_STATIC:BOOL=ON \ -DCLANG_BUILD_EXAMPLES:BOOL=OFF \ -DCLANG_CL:BOOL=OFF \ -DCLANG_ENABLE_ARCMT:BOOL=OFF \ -DCLANG_ENABLE_STATIC_ANALYZER:BOOL=OFF \ -DCLANG_INCLUDE_TESTS:BOOL=OFF \ -DHLSL_INCLUDE_TESTS:BOOL=OFF \ -DENABLE_SPIRV_CODEGEN:BOOL=ON \ -DSPIRV_BUILD_TESTS:BOOL=OFF %cmake_build --target dxc dxsc dxcompiler %install # DXC's cmake doesn't ship a clean `install` target by default for # our subset, so manually install the binaries + library to canonical # Fedora paths. The engine's runtime walker just needs `dxc` on PATH # (per Nick_L); shipping the supporting bits matches the bundled # layout for downstream consumers that may look for them. mkdir -p %{buildroot}%{_bindir} mkdir -p %{buildroot}%{_libdir} install -m 0755 %{_vpath_builddir}/bin/dxc %{buildroot}%{_bindir}/dxc install -m 0755 %{_vpath_builddir}/bin/dxsc %{buildroot}%{_bindir}/dxsc 2>/dev/null || : # libdxcompiler.so + versioned symlink (cmake build typically # produces both libdxcompiler.so and libdxcompiler.so.). install -m 0755 %{_vpath_builddir}/lib/libdxcompiler.so* %{buildroot}%{_libdir}/ %files %license LICENSE.TXT %{_bindir}/dxc %{_bindir}/dxsc %{_libdir}/libdxcompiler.so* %changelog * Fri May 08 2026 Nick Schuetz - 1.8.2505.1-1.rev13 - Versioned-major rename: o3de-dxc-spirv -> o3de2605-dxc-spirv. Mirrors the engine package's o3deNNNN naming convention so `o3de2605-dxc-spirv` and a future `o3de2610-dxc-spirv` can co-exist in the same COPR project, matching upstream's CDN model. Empirical research is captured in the o3de-rpm memory note `project_o3de_3p_versioning_research.md`. - Backward compat: Obsoletes + Provides headers so `dnf upgrade` transitions seamlessly from o3de-dxc-spirv rev1-rev12 (the PoC iteration history that landed the package green on 2026-05-08). - No functional change. Same 12 iterations of fixes carry forward; this revision is a name-only bump. * Fri May 08 2026 Nick Schuetz - 1.8.2505.1-1.rev12 - Fix: COPR build 10434595 (rev11) reached step 1106/1111 (the libdxcompiler.so link) and failed with the SAME `undefined reference to spvOptimizerOptions*` + `spvValidatorOptions*` + `spvtools::SpirvTools::*` symbols as rev10. The rev11 fix attempted to set the transitive `SPIRV-Tools-opt` → `SPIRV-Tools` edge via `target_link_libraries(SPIRV-Tools-opt INTERFACE SPIRV-Tools)` in Patch0001 — that form's INTERFACE_LINK_LIBRARIES doesn't reliably propagate to IMPORTED targets in this context (the link line still showed only `-lSPIRV-Tools-opt`). - Approach this time: fix at the consumer side instead of grafting a transitive edge on an IMPORTED target. clangSPIRV is what actually consumes the spv* C-API symbols, so its LINK_LIBS list should include both `SPIRV-Tools-opt` AND `SPIRV-Tools`. - Patch0001 reverted to its rev10 state (drop the rev11 transitive-link block, but keep the SPIRV-Headers + SPIRV-Tools find_package fallbacks + the SPIRV-Tools-static set_property guard). - New Patch0002: one-line addition of `SPIRV-Tools` to tools/clang/lib/SPIRV/CMakeLists.txt's LINK_LIBS list. Behavior-preserving in the bundled-SPIRV-Tools case (the bundled cmake's transitive already linked SPIRV-Tools; this just makes the link explicit on the consumer side, eliminating reliance on bundled-SPIRV-Tools cmake's implementation detail). * Thu May 07 2026 Nick Schuetz - 1.8.2505.1-1.rev11 - Fix: COPR build 10434564 (rev10) made enormous progress — reached step 1106/1111 (99.5%) before failing at the FINAL link of `libdxcompiler.so`: undefined reference to `spvOptimizerOptionsSetMaxIdBound' undefined reference to `spvOptimizerOptionsDestroy' These spv* C-API symbols live in libSPIRV-Tools.so (the main library, not the -opt variant). Link line included `-lSPIRV-Tools-opt` but NOT `-lSPIRV-Tools`. - Root cause: in the bundled-SPIRV-Tools case, `add_subdirectory(SPIRV-Tools)` natively sets up `SPIRV-Tools-opt` to depend on `SPIRV-Tools` transitively. Fedora's imported targets (SPIRV-ToolsConfig.cmake + SPIRV-Tools-optConfig.cmake) don't establish that transitive INTERFACE_LINK_LIBRARIES relationship — each is a standalone IMPORTED target. Combined with DXC's link-line flags `-Wl,-z,defs --as-needed`, the linker fails on every direct symbol reference that isn't in a directly-listed library. - Extend Patch0001's SPIRV-Tools fallback to call: target_link_libraries(SPIRV-Tools-opt INTERFACE SPIRV-Tools) This re-establishes the transitive dependency that the bundled cmake provides natively. Anything that links SPIRV-Tools-opt now transitively pulls in SPIRV-Tools too, satisfying the linker. - Architectural lesson: when patching cmake to use system imported targets in place of a bundled add_subdirectory, sometimes the imported targets don't cover the full link-graph that the bundled cmake established. Need to manually re-establish those edges. This is a known gotcha with cmake IMPORTED libraries. * Thu May 07 2026 Nick Schuetz - 1.8.2505.1-1.rev10 - Fix: COPR build 10434507 (rev9) reached step 484/1111 (44% — much further than rev7's 188/1111) before failing with typedef conflict between Fedora's `/usr/include/wsl/stubs/basetsd.h` and DXC's own `include/dxc/WinAdapter.h`: Fedora wsl/stubs: typedef uint32_t ULONG; typedef int32_t LONG; ... DXC WinAdapter.h: typedef unsigned long ULONG; typedef long LONG; ... These are structurally incompatible (LP64 native widths vs Win32 fixed widths). DXC's WinAdapter.h was designed assuming DXC's bundled DirectX-Headers submodule, which doesn't ship a wsl/stubs/ shim — Fedora's DirectX-Headers package adds that shim, hence the conflict. - Switch from system DirectX-Headers to bundled DirectX-Headers (Source2, pinned to DXC's exact submodule SHA: 980971e835876dc0cde415e8f9bc646e64667bf7 from microsoft/DirectX-Headers, verified via GitHub API: `gh api /repos/o3de/DirectXShaderCompiler/git/trees/release-1.8.2505.1-o3de:external`). Drop `BuildRequires: DirectX-Headers-devel` and the `-DDIRECTX_HEADER_INCLUDE_DIR=/usr/include` cmake flag. Update %prep to extract Source2 into external/DirectX-Headers/ instead of rmdir-ing the placeholder. DXC's existing add_subdirectory(${DXC_EXTERNAL_ROOT_DIR}/DirectX-Headers) branch builds it normally, no patching of DXC's external/CMakeLists.txt needed for the DirectX-Headers part. - Architectural lesson: Fedora's DirectX-Headers is fine as a system library for projects that DON'T have their own Win-types compat layer. DXC has its own (WinAdapter.h), and the two layers can't coexist. Stage 1-style "use system Foo" doesn't work universally; some 3rdParty deps need to be bundled-as-source because of internal architectural assumptions. - License of bundled DirectX-Headers: MIT (Microsoft) — Fedora-acceptable. * Thu May 07 2026 Nick Schuetz - 1.8.2505.1-1.rev9 - Fix: COPR build 10434109 (rev8) failed in 7m on F44 with `fatal error: d3d12shader.h: No such file or directory`. The compile command shows DXC was emitting `-I/usr/include/directx/directx -I/usr/include/directx/wsl/stubs` — meaning DXC's source code does `${DIRECTX_HEADER_INCLUDE_DIR}/directx` and `${DIRECTX_HEADER_INCLUDE_DIR}/wsl/stubs` expansions, expecting an `include/`-style ROOT that contains a `directx/` subdir (mirroring upstream DirectX-Headers' submodule layout: `external/DirectX-Headers/include/directx/d3d12shader.h`). Fedora's layout has the headers directly in `/usr/include/directx/`, so the correct DIRECTX_HEADER_INCLUDE_DIR is `/usr/include` (not `/usr/include/directx`) — DXC's downstream `${DIR}/directx` then resolves to `/usr/include/directx`, finding `d3d12shader.h` correctly. * Thu May 07 2026 Nick Schuetz - 1.8.2505.1-1.rev8 - Fix: COPR build 10434105 (rev7) failed in 2m02s on F44 — got past cmake config and into actual compilation (step 188/1111) before failing at `utils/version/dxcversion.inc.gen` because DXC's build invokes `git rev-parse HEAD` to embed the commit hash and `git` isn't installed in the COPR mock chroot. Trivial: add `BuildRequires: git`. - Forward-progress check: rev7 reached deep compilation (TableGen tools building, llvm-tblgen linking) — the BUILD_SHARED_LIBS=OFF + Patch0001 + rmdir fixes from rev6/rev5/rev4 all held. Only the `git` BR was missing. * Thu May 07 2026 Nick Schuetz - 1.8.2505.1-1.rev7 - Fix: COPR build 10434098 (rev6) failed in 18s on F44 with cmake error "Cyclic dependencies are allowed only among static libraries" — the rev6 fixes (rmdir empty submodules + Patch0001 system-spirv fallback) worked correctly and got the build past the SPIR-V dependency setup, but Fedora's %%cmake macro sets BUILD_SHARED_LIBS:BOOL=ON by default, which conflicts with DXC's clang-as-static-libraries expectation (clangAST / clangCodeGen / clangSema / clangFrontend etc. have inter-target cyclic deps that are only legal among STATIC_LIBRARY targets, per cmake's policy — modular LLVM/Clang builds rely on static-only linkage). - Fix: explicitly pass `-DBUILD_SHARED_LIBS:BOOL=OFF` to override the Fedora macro default. Restores DXC's expected static-everywhere link model. Combined with LIBCLANG_BUILD_STATIC=ON (already set), the resulting libdxcompiler.so remains self-contained. - Strategic context: this is iteration 4 (rev4 → rev5 → rev6 → rev7). Each iteration has produced a new failure mode, with the fix making forward progress in the build pipeline: rev4: empty submodule dirs at cmake-config. rev5: Patch0001 logic correct but IS_DIRECTORY edge case. rev6: BUILD_SHARED_LIBS conflicts with DXC's static-clang assumption. rev7: this — should reach actual compilation. * Thu May 07 2026 Nick Schuetz - 1.8.2505.1-1.rev6 - Fix: COPR build 10434076 (rev5) failed in 1m08s on F44 with the same "SPIRV-Headers was not found" symptom as rev4 — the rev5 patch logic was correct but missed an edge case: the `git archive`-generated tarball leaves the three submodule directories present-but-empty, so DXC's `IS_DIRECTORY ${DXC_SPIRV_HEADERS_DIR}` test returns TRUE and cmake falls into the `add_subdirectory` branch (which fails because the dir has no CMakeLists.txt) BEFORE reaching Patch0001's else()-branch fallback. - Fix: add `rmdir external/{DirectX-Headers,SPIRV-Headers,SPIRV-Tools}` in %prep so IS_DIRECTORY returns FALSE and Patch0001's system-find_package fallback fires. The rmdir succeeds for empty dirs (placeholders) and is a no-op (`|| :`) if a future tarball ever includes populated submodules. * Thu May 07 2026 Nick Schuetz - 1.8.2505.1-1.rev5 - Fix: COPR build 10433445 (rev4) failed in 52s on F44/F43/rawhide with "SPIRV-Headers was not found" — DXC's source tree references external/{DirectX-Headers,SPIRV-Headers,SPIRV-Tools} as git submodules, but our tarball was created via plain `git archive` (non-recursive), leaving those directories empty in the SRPM. - Patch0001: add system-package fallback to DXC's external/CMakeLists.txt: - SPIRV-Headers: find_package(SPIRV-Headers) + set SPIRV-Headers_SOURCE_DIR to /usr (so `${SPIRV-Headers_SOURCE_DIR}/include` resolves to /usr/include/spirv/... where Fedora ships spirv.hpp etc). - SPIRV-Tools: find_package(SPIRV-Tools) + find_package(SPIRV-Tools-opt). - Wrap set_property(TARGET SPIRV-Tools-static ...) in `if (TARGET ...)` because Fedora ships only SPIRV-Tools (SHARED IMPORTED), not static. - BuildRequires: spirv-headers-devel + spirv-tools-devel + DirectX-Headers-devel. - cmake -DDIRECTX_HEADER_INCLUDE_DIR=/usr/include/directx — bypasses DXC's DirectX-Headers-submodule lookup (Fedora's DirectX-Headers ships no cmake config, so we pass the include dir directly). - Strategic context: same audit-pattern shape as the engine's Stage 1 swaps — use Fedora's license-clean SPIR-V packages instead of bundling submodule sources. Cleaner from a packaging-review perspective + reproducible builds. * Thu May 07 2026 Nick Schuetz - 1.8.2505.1-1.rev4 - Initial PoC: license-clean Linux DXC build for O3DE. - Source: o3de/DirectXShaderCompiler at release-1.8.2505.1-o3de (matches o3de/3p-package-source's package-system/DirectXShaderCompiler build_config.json git_tag, package_version 1.8.2505.1-o3de-rev4). - Cmake flags mirror the upstream build_config.json's Linux config. - LLVM_TARGETS_TO_BUILD=None + ENABLE_SPIRV_CODEGEN=ON: no DXIL Windows-signing tooling included; SPIR-V codegen only. - LIBCLANG_BUILD_STATIC=ON: libdxcompiler.so self-contained, no embedded libclang-12.so.* runtime requirement on the consumer side. - License: NCSA + Apache-2.0 (with LLVM exception). Both Fedora-compatible.