From 5d19cfaec9b6f3b4114c86098c4a9bdd66c19f55 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 5 May 2026 13:16:08 +0200 Subject: [PATCH] PHPC-2647, PHPC-2715: Fix all possible build configurations (standalone vs. in-tree, in-source vs. out-of-source) (#2014) * PHPC-2647: Write generated config headers to extension build directory Use PHP_EXT_BUILDDIR as the base for all AC_CONFIG_FILES paths so that generated config headers (common-config.h, bson/config.h, mongoc-config.h, etc.) are written to the extension's build directory rather than its source directory, keeping the source tree clean for out-of-source builds. Add PHP_MONGODB_ADD_BUILD_INCLUDE to php_mongodb.m4 as the counterpart to PHP_MONGODB_ADD_INCLUDE: it adds a compiler include path relative to the extension build directory (PHP_EXT_BUILDDIR), which is needed so the compiler can find the generated config headers regardless of whether the build is in-source or out-of-source. Call PHP_MONGODB_ADD_BUILD_INCLUDE for each directory that receives a generated header via AC_CONFIG_FILES: common/src, libbson/src/bson, libmongoc/src/mongoc, and conditionally zlib-1.3.1 and libmongocrypt/src. * Test both in-source and out-of-source for in-tree builds * Correctly expand build directory before adding as include * Fail on unsupported modes * Fix comment to match matrix value (in-source, not from-source) --- .github/workflows/tests.yml | 37 +++++++++++++++---- config.m4 | 57 ++++++++++++----------------- scripts/autotools/m4/php_mongodb.m4 | 22 +++++++++++ 3 files changed, 76 insertions(+), 40 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 78049e105..1b654a882 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -240,12 +240,21 @@ jobs: # --enable-mongodb instead of --enable-mongodb=shared), as done by projects # like StaticPHP. This exercises the PHP in-tree build path where configure # is invoked from the PHP source root rather than the extension directory. - test-static-php-build: - name: "Static PHP Build" + # Two modes are tested: + # in-source — configure and build run from the PHP source directory + # (PHP source dir = PHP build dir, layout 3) + # out-of-source — configure and build run from a separate build directory + # (PHP source dir ≠ PHP build dir, layout 4) + test-in-tree-build: + name: "Static PHP Build (${{ matrix.mode }})" runs-on: "ubuntu-latest" env: PHP_VERSION: "8.5.5" + strategy: + matrix: + mode: ['in-source', 'out-of-source'] + steps: - name: "Checkout" uses: "actions/checkout@v6" @@ -276,24 +285,38 @@ jobs: - name: "Generate PHP build scripts" run: cd "$GITHUB_WORKSPACE/php-src" && ./buildconf --force + - name: "Set build directory" + run: | + if [ "${{ matrix.mode }}" = "out-of-source" ]; then + mkdir -p /tmp/php-build + echo "PHP_BUILD_DIR=/tmp/php-build" >> "$GITHUB_ENV" + elif [ "${{ matrix.mode }}" = "in-source" ]; then + echo "PHP_BUILD_DIR=$GITHUB_WORKSPACE/php-src" >> "$GITHUB_ENV" + else + echo "Invalid mode" + exit 1 + fi + # Note: --with-openssl is needed for the bundled libmongoc's TLS support. - name: "Configure PHP with MongoDB extension (static)" run: | - cd "$GITHUB_WORKSPACE/php-src" - ./configure \ + [ -n "$PHP_BUILD_DIR" ] || { echo "PHP_BUILD_DIR is not set"; exit 1; } + "$GITHUB_WORKSPACE/php-src/configure" \ --enable-debug \ --enable-cli \ --enable-mongodb \ --enable-mongodb-developer-flags \ --with-openssl + working-directory: ${{ env.PHP_BUILD_DIR }} - name: "Build PHP" - run: cd "$GITHUB_WORKSPACE/php-src" && make -j$(nproc) + run: make -j$(nproc) + working-directory: ${{ env.PHP_BUILD_DIR }} - name: "Verify MongoDB extension is compiled in" run: | - "$GITHUB_WORKSPACE/php-src/sapi/cli/php" -m | grep -ix mongodb - "$GITHUB_WORKSPACE/php-src/sapi/cli/php" --ri mongodb + "$PHP_BUILD_DIR/sapi/cli/php" -m | grep -ix mongodb + "$PHP_BUILD_DIR/sapi/cli/php" --ri mongodb test-out-of-source-build: name: "Out-of-source Build" diff --git a/config.m4 b/config.m4 index e325d5f7a..a1830f3ef 100644 --- a/config.m4 +++ b/config.m4 @@ -374,27 +374,6 @@ if test "$PHP_MONGODB" != "no"; then PHP_MONGODB_ADD_SOURCES([src/libmongoc/src/libbson/src/jsonsl/], $PHP_MONGODB_JSONSL_SOURCES, $PHP_MONGODB_BUNDLED_CFLAGS) PHP_MONGODB_ADD_SOURCES([src/libmongoc/src/libmongoc/src/mongoc/], $PHP_MONGODB_MONGOC_SOURCES, $PHP_MONGODB_BUNDLED_CFLAGS) - dnl TODO: Use $ext_builddir/$ext_srcdir once this block can move after PHP_NEW_EXTENSION. - dnl $ext_builddir and $ext_srcdir are set by PHP_NEW_EXTENSION, but PHP_ADD_INCLUDE - dnl and PHP_MONGODB_ADD_SOURCES calls must precede PHP_NEW_EXTENSION, so the whole - dnl block cannot be deferred. PHP_EXT_BUILDDIR/PHP_EXT_SRCDIR are M4 macros that - dnl are always available and provide equivalent values without that constraint. - dnl - dnl PHP_EXT_BUILDDIR expands to the extension's directory relative to the build - dnl root: "ext/mongodb" for PHP in-tree builds, "." for phpize builds. Pairing - dnl it with $abs_builddir (the absolute path to wherever configure was invoked) - dnl produces the correct absolute path to the generated config headers regardless - dnl of build layout. Using $PWD here breaks PHP in-tree builds because $PWD is - dnl the PHP source/build root, not the extension's subdirectory within it. - php_mongodb_ext_builddir=PHP_EXT_BUILDDIR(mongodb) - php_mongodb_ext_srcdir=PHP_EXT_SRCDIR(mongodb) - - dnl Add the build directories as include paths so the compiler finds generated - dnl config headers (common-config.h, bson/config.h, mongoc-config.h, etc.). - PHP_ADD_INCLUDE([$abs_builddir/$php_mongodb_ext_builddir/src/libmongoc/src/common/src]) - PHP_ADD_INCLUDE([$abs_builddir/$php_mongodb_ext_builddir/src/libmongoc/src/libbson/src]) - PHP_ADD_INCLUDE([$abs_builddir/$php_mongodb_ext_builddir/src/libmongoc/src/libmongoc/src]) - PHP_MONGODB_ADD_INCLUDE([src/libmongoc/src/common/src/]) PHP_MONGODB_ADD_INCLUDE([src/libmongoc/src/uthash/]) PHP_MONGODB_ADD_INCLUDE([src/libmongoc/src/libbson/src/]) @@ -415,17 +394,26 @@ if test "$PHP_MONGODB" != "no"; then PHP_MONGODB_ADD_BUILD_DIR([src/libmongoc/src/kms-message/src/]) fi - dnl Write generated config headers into the extension's build directory - dnl (${php_mongodb_ext_builddir}/... relative to the configure invocation directory). - dnl For standalone out-of-source builds this stays in the build tree; for - dnl PHP in-tree builds it lands under ext/mongodb/ rather than the PHP root. + dnl PHP_EXT_BUILDDIR expands to "ext/mongodb" for PHP in-tree builds and + dnl "." for phpize builds. Captured as a shell variable here because + dnl AC_CONFIG_FILES paths are expanded at configure run time, not at M4 + dnl processing time. + mongodb_builddir=PHP_EXT_BUILDDIR(mongodb) + + dnl Generated config headers are written into the extension build directory. + dnl For standalone out-of-source builds they stay in the build tree; for PHP + dnl in-tree builds they land under ext/mongodb/ rather than the PHP root. + PHP_MONGODB_ADD_BUILD_INCLUDE([src/libmongoc/src/common/src/]) + PHP_MONGODB_ADD_BUILD_INCLUDE([src/libmongoc/src/libbson/src/]) + PHP_MONGODB_ADD_BUILD_INCLUDE([src/libmongoc/src/libmongoc/src/]) + AC_CONFIG_FILES([ - ${php_mongodb_ext_srcdir}/src/libmongoc/src/common/src/common-config.h - ${php_mongodb_ext_srcdir}/src/libmongoc/src/libbson/src/bson/config.h - ${php_mongodb_ext_srcdir}/src/libmongoc/src/libbson/src/bson/version.h - ${php_mongodb_ext_srcdir}/src/libmongoc/src/libmongoc/src/mongoc/mongoc-config.h - ${php_mongodb_ext_srcdir}/src/libmongoc/src/libmongoc/src/mongoc/mongoc-config-private.h - ${php_mongodb_ext_srcdir}/src/libmongoc/src/libmongoc/src/mongoc/mongoc-version.h + ${mongodb_builddir}/src/libmongoc/src/common/src/common-config.h + ${mongodb_builddir}/src/libmongoc/src/libbson/src/bson/config.h + ${mongodb_builddir}/src/libmongoc/src/libbson/src/bson/version.h + ${mongodb_builddir}/src/libmongoc/src/libmongoc/src/mongoc/mongoc-config.h + ${mongodb_builddir}/src/libmongoc/src/libmongoc/src/mongoc/mongoc-config-private.h + ${mongodb_builddir}/src/libmongoc/src/libmongoc/src/mongoc/mongoc-version.h ]) if test "x$bundled_utf8proc" = "xyes"; then @@ -440,7 +428,8 @@ if test "$PHP_MONGODB" != "no"; then PHP_MONGODB_ADD_SOURCES([src/libmongoc/src/zlib-1.3.1/], $PHP_MONGODB_ZLIB_SOURCES, $PHP_MONGODB_ZLIB_CFLAGS) PHP_MONGODB_ADD_INCLUDE([src/libmongoc/src/zlib-1.3.1/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongoc/src/zlib-1.3.1/]) - AC_CONFIG_FILES([${php_mongodb_ext_srcdir}/src/libmongoc/src/zlib-1.3.1/zconf.h]) + PHP_MONGODB_ADD_BUILD_INCLUDE([src/libmongoc/src/zlib-1.3.1/]) + AC_CONFIG_FILES([${mongodb_builddir}/src/libmongoc/src/zlib-1.3.1/zconf.h]) fi if test "$PHP_MONGODB_CLIENT_SIDE_ENCRYPTION" = "yes"; then @@ -478,8 +467,10 @@ if test "$PHP_MONGODB" != "no"; then PHP_MONGODB_ADD_BUILD_DIR([src/libmongocrypt/src/unicode/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongocrypt/kms-message/src/]) + PHP_MONGODB_ADD_BUILD_INCLUDE([src/libmongocrypt/src/]) + AC_CONFIG_FILES([ - ${php_mongodb_ext_srcdir}/src/libmongocrypt/src/mongocrypt-config.h + ${mongodb_builddir}/src/libmongocrypt/src/mongocrypt-config.h ]) fi fi diff --git a/scripts/autotools/m4/php_mongodb.m4 b/scripts/autotools/m4/php_mongodb.m4 index d846c0bf6..5f5cfd0c1 100644 --- a/scripts/autotools/m4/php_mongodb.m4 +++ b/scripts/autotools/m4/php_mongodb.m4 @@ -40,6 +40,28 @@ AC_DEFUN([PHP_MONGODB_ADD_INCLUDE],[ PHP_ADD_INCLUDE(PHP_EXT_SRCDIR(mongodb)[/][$1]) ]) +dnl +dnl PHP_MONGODB_ADD_BUILD_INCLUDE(path) +dnl +dnl Adds an include path relative to the extension build directory (i.e. +dnl PHP_EXT_BUILDDIR). Use this for directories containing generated files +dnl (e.g. config headers written by AC_CONFIG_FILES). +dnl +dnl PHP_EXT_BUILDDIR returns a path relative to the configure invocation +dnl directory (e.g. "." for phpize builds, "ext/mongodb" for in-tree builds). +dnl The subdirectory passed as $1 does not exist at configure time (build dirs +dnl are created in AC_CONFIG_COMMANDS_PRE), so passing the full relative path +dnl to PHP_ADD_INCLUDE would cause PHP_EXPAND_PATH to silently discard it when +dnl the "cd $path && pwd" probe fails. To avoid this, we resolve only the base +dnl (PHP_EXT_BUILDDIR, which always exists at configure time) to an absolute +dnl path first, then append $1. PHP_ADD_INCLUDE skips the cd-probe for paths +dnl that already start with "/". +dnl +AC_DEFUN([PHP_MONGODB_ADD_BUILD_INCLUDE],[ + PHP_EXPAND_PATH(PHP_EXT_BUILDDIR(mongodb), php_mongodb_abs_builddir) + PHP_ADD_INCLUDE([$php_mongodb_abs_builddir/$1]) +]) + dnl dnl PHP_MONGODB_ADD_BUILD_DIR(path) dnl