# o3de-mcpp-az -- license-clean mcpp library for Open 3D Engine # # Builds the mcpp 2.7.2 portable C preprocessor with Amazon Lumberyard's # `_az.2` patch series applied. Library-link variant of the DXC and # SPIRV-Cross PoCs (those are binary-shellout tools; mcpp is a library # the engine #includes via and calls in-process). # # Per the audit at 2026-05-08 (see o3de-rpm/BUNDLED_LIBRARIES.md # "Binary-only / DXC-class dependencies"): the engine consumes mcpp's # C library API directly (Gems/Atom/Asset/Shader/Code/Source/Editor/ # CommonFiles/Preprocessor.cpp uses mcpp_lib_main, mcpp_set_out_func, # mcpp_set_report_include_callback). Replacing with another preprocessor # would require engine code changes; the practical Fedora-track answer # is a license-clean COPR rebuild of mcpp itself. # # Upstream: https://mcpp.sourceforge.net/ (Kiyoshi Matsui; # last release 2.7.2, 2008; abandonware-class but still BSD-2-Clause # license-clean and the C-preprocessor problem is genuinely solved). # # The `_az.2` patch series (566 lines, 11 hunks) covers: # - aarch64 host triplet detection in config.guess # - COMPILER macro defaults adjusted for Lumberyard build expectations # - whitespace + style cleanup # - small build-system tweaks # Sourced verbatim from o3de/3p-package-source/package-system/mcpp/ # mcpp_2.7.2_az.patch (the engine's own canonical patch set). # # This is the "PoC" stage; pairs with the deferred mcpp PoC entry in # o3de-rpm/FOLLOW_UPS.md. Goal of this iteration: produce libmcpp.so + # /usr/include/mcpp_lib.h that the o3de engine's CMakeLists can link # against in place of the bundled mcpp-2.7.2_az.2-rev1 fetch. %global mcpp_pkgrev rev8 # Versioned-major naming: package name carries the engine-major suffix so # `o3de2605-mcpp-az` and a future `o3de2610-mcpp-az` can co-exist in the # same `hellaenergy/o3de-dependencies` COPR project. Each engine-major # specs Requires/BuildRequires its own version of this package, isolating # ABI/API at the package level and matching upstream's CDN keying model # (see `project_o3de_3p_versioning_research.md` memory note for the # empirical research that drove this decision). Name: o3de2605-mcpp-az Version: 2.7.2 Release: 1.%{mcpp_pkgrev}%{?dist} Summary: Portable C preprocessor (Amazon-patched fork) for Open 3D Engine 26.05 License: BSD-2-Clause URL: https://mcpp.sourceforge.net/ # Replace the unversioned o3de-mcpp-az (PoC iterations rev1-rev7) so dnf # upgrade transitions cleanly from the old name. Provides keeps any # external Requires lines on the old name resolving until they migrate. Obsoletes: o3de-mcpp-az < 2.7.2-1.rev8 Provides: o3de-mcpp-az = %{version}-%{release} # Source0: upstream mcpp 2.7.2 tarball, fetched from sourceforge.net. # We don't fetch directly via wget in %prep because COPR builders run # with enable_net=false for license-clean repos; pre-staged tarball is # the canonical input. SHA256 baked into the spec for integrity. Source0: mcpp-%{version}.tar.gz # Patch0001: Lumberyard's `_az.2` patch series, sourced verbatim from # o3de/3p-package-source/package-system/mcpp/mcpp_2.7.2_az.patch. # Contains 566 lines across 11 hunks. Apache-2.0 OR MIT licensed # (per o3de/3p-package-source LICENSE). Compatible with the upstream # BSD-2-Clause mcpp source; no licensing conflict. Patch0001: mcpp_2.7.2_az.patch BuildRequires: gcc BuildRequires: make BuildRequires: autoconf BuildRequires: automake # mcpp's configure.ac uses libtool macros (AC_LIBTOOL_WIN32_DLL, # AC_PROG_LIBTOOL); autoreconf needs libtool's m4 files installed. BuildRequires: libtool # mcpp uses GNU autotools (./configure + make). %description mcpp -- Matsuui's C/C++ preprocessor, a portable C preprocessor library + standalone command-line tool. This build is the Amazon Lumberyard fork's `_az.2` patch series applied to upstream mcpp 2.7.2 sources. Used by Open 3D Engine's AZSL (Amazon Shader Language) asset-build pipeline -- the engine `#include`s `` and calls `mcpp_lib_main()`, `mcpp_set_out_func()`, `mcpp_set_report_include_callback()` to expand `#ifdef`s in shader source files at asset-build time. This package replaces the bundled mcpp-2.7.2_az.2-rev1 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 or that prefer to consume from their own COPR infrastructure. License: BSD-2-Clause (upstream) + Apache-2.0 OR MIT (Lumberyard patches). Both Fedora-compatible. %package devel Summary: Development headers + static library for %{name} Requires: %{name}%{?_isa} = %{version}-%{release} # Replace the unversioned o3de-mcpp-az-devel from PoC iterations rev1-rev7. Obsoletes: o3de-mcpp-az-devel < 2.7.2-1.rev8 Provides: o3de-mcpp-az-devel = %{version}-%{release} %description devel Development headers (mcpp_lib.h) and static archive (libmcpp.a) for the %{name} library. Install this in addition to %{name} when building software (e.g. Open 3D Engine) that links against mcpp's preprocessor C API. %prep %autosetup -n mcpp-%{version} -p1 # Regenerate autoconf machinery in case the patched sources need it. # autoreconf is conservative -- only updates files where the patched # source has newer timestamps than the generated artefacts. autoreconf -fi %build # mcpp 2.7.2 was written in 2008 and predates much of the modern C # standard tightening. Fedora 44's GCC 14 default rejects several # implicit conversions that mcpp's source uses freely (incompatible # pointer types in main.c / expand.c, "expected ',' or ';' before # 'LL_FORM'" in eval.c). Downgrade these to warnings via CFLAGS; # o3de/3p-package-source/.../mcpp/get_and_build_mcpp.py applies a # similar workaround on Mac (--Wno-implicit-function-declaration). # The output binary + library work correctly regardless; this is purely # a build-time C-strictness mismatch. export CFLAGS="${CFLAGS} \ -std=gnu99 \ -Wno-error=incompatible-pointer-types \ -Wno-error=implicit-function-declaration \ -Wno-error=int-conversion \ -Wno-error=implicit-int" # -std=gnu99 needed because GCC 14 defaults to gnu23, where `true` and # `false` became reserved keywords. mcpp 2.7.2 uses them freely as # identifiers (system.c:3434, 3461, 3466, etc.). Falling back to the # C99 standard makes them ordinary identifiers again. Same idiom for # similar-aged C codebases (Lua's pre-5.4 sources, several TclLib # packages, etc.). # mcpp's configure-time AC_RUN_IFELSE test for the printf length # modifier of `long long` (which sets LL_FORM via AC_DEFINE) compiles # a K&R-style test program (`int strcmp();` without prototype). On # modern GCC that test program fails to compile under default # strictness, the AC_RUN_IFELSE falls into its action-if-false branch # (which is empty in mcpp's configure.ac), and LL_FORM never gets # defined in src/config.h. eval.c then fails with # "expected ',' or ';' before 'LL_FORM'" at compile time. # # Brute-force fix: define LL_FORM directly via CPPFLAGS so eval.c # always sees the macro regardless of what configure decided. "ll" is # the C99 standard length modifier for `long long` and is correct on # all platforms o3de targets (Linux x86_64 + aarch64). HAVE_LONG_LONG # defined for completeness; it's already true on every modern Linux, # but explicit beats relying on configure's other AC_RUN_IFELSE checks. export CPPFLAGS="${CPPFLAGS} -DLL_FORM=\\\"ll\\\" -DHAVE_LONG_LONG=1" # Per o3de/3p-package-source/package-system/mcpp/get_and_build_mcpp.py: # ./configure --with-pic --enable-mcpplib # `--with-pic` builds position-independent code (required for shared # library output and engine asset-builder linkage). # `--enable-mcpplib` builds mcpp as a library in addition to the # standalone command-line tool. %configure --with-pic --enable-mcpplib %make_build %install %make_install # mcpp's autotools install puts: # /usr/bin/mcpp -- standalone preprocessor binary # /usr/lib64/libmcpp.so.0.1.0 -- shared library (versioned) # /usr/lib64/libmcpp.so.0 -- soname symlink # /usr/lib64/libmcpp.so -- devel symlink # /usr/lib64/libmcpp.a -- static archive # /usr/lib64/libmcpp.la -- libtool archive (we'll remove) # /usr/include/mcpp_lib.h -- public header # /usr/include/mcpp_out.h -- public header # /usr/share/info/... -- texinfo docs # # Remove the .la file (Fedora policy for plain shared libs). rm -f %{buildroot}%{_libdir}/libmcpp.la # autotools `make install` writes upstream's docs to /usr/share/doc/mcpp/ # (LICENSE, NEWS, README, mcpp-manual{,-jp}.html). Two problems: # 1. The directory name "mcpp" doesn't match the package name; rpm's # %doc directive owns /usr/share/doc/o3de-mcpp-az/. # 2. LICENSE duplicates what %license already installs. # Simplest: drop the whole autotools doc tree and rely on rpm's %doc # directive (below) to copy README/NEWS/ChangeLog from the source tree # to the conventional /usr/share/doc/o3de-mcpp-az/ location. Engine code # doesn't need the HTML manuals. rm -rf %{buildroot}%{_docdir}/mcpp %files %license LICENSE %doc ChangeLog README NEWS %{_bindir}/mcpp %{_libdir}/libmcpp.so.* %{_mandir}/man1/mcpp.1* %files devel %{_includedir}/mcpp_lib.h %{_includedir}/mcpp_out.h %{_libdir}/libmcpp.so %{_libdir}/libmcpp.a %changelog * Fri May 08 2026 Nick Schuetz - 2.7.2-1.rev8 - Versioned-major rename: o3de-mcpp-az -> o3de2605-mcpp-az. Mirrors the engine package's o3deNNNN naming convention so `o3de2605-mcpp-az` and a future `o3de2610-mcpp-az` can co-exist in the same COPR project, matching upstream's CDN model (multiple engine-major lines pinning different package versions side-by-side). Empirical research on the decision is captured in the o3de-rpm memory note `project_o3de_3p_versioning_research.md`; downsides-of-waiting analysis is what motivated doing it now (~10 testers, three Stage 2 PoCs just landed, naming convention not yet hardened anywhere). - Backward compat: Obsoletes + Provides headers on both the main and -devel subpackage so `dnf upgrade` transitions seamlessly from the unversioned o3de-mcpp-az / o3de-mcpp-az-devel to the new versioned names without user intervention. * Fri May 08 2026 Nick Schuetz - 2.7.2-1.rev7 - Fix: COPR build 10436690 (rev6) failed at %files-check stage with six unpackaged files: /usr/share/doc/mcpp/{LICENSE,NEWS,README,mcpp-manual.html,mcpp-manual-jp.html} /usr/share/man/man1/mcpp.1.gz rev6 trimmed too aggressively; autotools `make install` writes upstream docs to /usr/share/doc/mcpp/ which our %doc directive (which owns /usr/share/doc/o3de-mcpp-az/) doesn't cover, plus the man page wasn't listed in %files at all. - Fix: drop the autotools-installed /usr/share/doc/mcpp/ tree in %install (LICENSE is duplicated by %license; README/NEWS/ChangeLog come via the %doc directive from source; HTML manuals not needed for engine consumers). Add /usr/share/man/man1/mcpp.1* to the main %files so the CLI tool's man page ships. * Fri May 08 2026 Nick Schuetz - 2.7.2-1.rev6 - Fix: COPR build 10436667 (rev5) succeeded at compile -- BIG WIN, the -std=gnu99 + LL_FORM CPPFLAGS + CFLAGS workarounds + libtool BR all combined to make mcpp 2.7.2 build cleanly on Fedora 44 GCC 14. But the build then failed at the rpmbuild %files packaging stage: error: File not found: BUILDROOT/usr/share/info/mcpp*.info* error: File not found: BUILDROOT/usr/share/doc/o3de-mcpp-az/AUTHORS - Fix: drop AUTHORS from %doc (upstream tarball doesn't ship one; only README, NEWS, ChangeLog, INSTALL, LICENSE are present) and drop the %{_infodir}/mcpp*.info* entry (info docs aren't generated by default, and the engine doesn't need them anyway). - This iteration is the smallest fix yet -- just trimming the %files list to match what's actually in BUILDROOT. * Fri May 08 2026 Nick Schuetz - 2.7.2-1.rev5 - Fix: COPR build 10436650 (rev4) failed in 4m at compile-time: system.c:3434:15: error: expected identifier or '*' before 'true' system.c:3461:19: error: expected identifier or '*' before 'false' system.c:3515:5: error: expected ';' before ':' token rev4's CPPFLAGS bypass for LL_FORM worked (LL_FORM is now defined), but GCC 14 defaults to gnu23 where `true` and `false` became reserved keywords. mcpp 2.7.2 (2008-vintage) uses them freely as identifiers. - Fix: add `-std=gnu99` to CFLAGS so `true`/`false` become ordinary identifiers again. Standard idiom for similar-aged C codebases. * Fri May 08 2026 Nick Schuetz - 2.7.2-1.rev4 - Fix: COPR build 10436630 (rev3) failed in 3m at compile-time: eval.c:1284:22: error: expected ',' or ';' before 'LL_FORM' eval.c:1638:51: error: expected ',' or ';' before 'LL_FORM' rev3's CFLAGS workaround handled the pointer-type errors, but LL_FORM is undefined. - Diagnosis: mcpp's configure-time AC_RUN_IFELSE test for the printf length modifier of `long long` (which AC_DEFINEs LL_FORM) compiles a K&R-style test program (`int strcmp();` without prototype). On modern GCC the test program fails to compile under default strictness, the AC_RUN_IFELSE falls into its action-if-false branch (which is empty in mcpp's configure.ac), and LL_FORM never gets written into src/config.h. - Brute-force fix: define LL_FORM + HAVE_LONG_LONG via CPPFLAGS so eval.c always sees them regardless of what configure decided. "ll" is the C99 standard length modifier for `long long` and correct on all platforms o3de targets. * Fri May 08 2026 Nick Schuetz - 2.7.2-1.rev3 - Fix: COPR build 10436573 (rev2) failed in 4m at compile-time with GCC 14 strictness errors against mcpp 2.7.2's 2008-vintage C source: main.c:371: incompatible pointer type passing arg 2 of do_options eval.c:1284: expected ',' or ';' before 'LL_FORM' macro expand.c:713: assignment to 'char *' from incompatible 'LOCATION *' These are all pre-modern-C strictness violations that GCC tightened from warnings to errors over the years. - Add CFLAGS workaround in %build to downgrade these specific errors back to warnings: -Wno-error=incompatible-pointer-types -Wno-error=implicit-function-declaration -Wno-error=int-conversion -Wno-error=implicit-int Same shape as o3de/3p-package-source/.../mcpp/get_and_build_mcpp.py's Mac workaround (--Wno-implicit-function-declaration). Output binary + library are correct regardless; this is purely a build-time C-strictness mismatch. * Fri May 08 2026 Nick Schuetz - 2.7.2-1.rev2 - Fix: COPR build 10436552 (rev1) failed in 10s with autoreconf error "configure.ac:20: error: possibly undefined macro: AC_LIBTOOL_WIN32_DLL". mcpp's configure.ac uses libtool macros; autoreconf needs libtool's m4 files installed. Add `BuildRequires: libtool`. Trivial. * Fri May 08 2026 Nick Schuetz - 2.7.2-1.rev1 - Initial PoC: license-clean mcpp library + binary build for O3DE. - Source: upstream mcpp 2.7.2 tarball from sourceforge.net (Kiyoshi Matsui, BSD-2-Clause). Last upstream release 2008; abandonware-class but the C preprocessor problem is solved and the source is small + stable. - Patch0001: Amazon Lumberyard `_az.2` patch series, sourced verbatim from o3de/3p-package-source/package-system/mcpp/mcpp_2.7.2_az.patch. 566 lines, 11 hunks. Covers aarch64 host triplet detection, COMPILER macro defaults, whitespace cleanup, build-system tweaks. Apache-2.0 OR MIT licensed; compatible with BSD-2-Clause upstream. - Configure flags mirror o3de/3p-package-source/.../mcpp/ get_and_build_mcpp.py's Linux config: ./configure --with-pic --enable-mcpplib --with-pic builds PIC for shared library / engine builder linkage; --enable-mcpplib builds the in-process library in addition to the standalone CLI tool. - Sibling track to o3de-dxc-spirv (binary shellout) and o3de-spirv-cross (binary shellout): mcpp is the LIBRARY-LINK variant of the DXC-class binary-only dependency pattern. Engine code in Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/Preprocessor.cpp calls mcpp_lib_main / mcpp_set_out_func / mcpp_set_report_include_callback at asset-build time. - Engine-side glue (LY_USE_SYSTEM_MCPP bcond + Find shim or install-time symlink overlay) follows in a separate o3de-rpm spec edit once this PoC RPM lands green.