{"thread":{"id":"62804","subject":"[PATCH v2 01/11] GIT-VERSION-GEN: simplify computing the dirty marker","startedAt":"2025-01-14T11:56:18Z","lastAt":"2025-01-22T12:05:09Z","messageCount":18,"participants":["Patrick Steinhardt","Junio C Hamano","Toon Claes"],"isPatch":true,"patchVersion":2,"patchTotal":11},"messages":[{"id":"510497","messageId":"20250114-b4-pks-meson-additions-v2-0-8d7ec676cfd9@pks.im","threadId":"62804","inReplyTo":"20250113-b4-pks-meson-additions-v1-0-97f6a93f691d@pks.im","subject":"[PATCH v2 00/11] meson: a couple of additions","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-01-14T11:56:10Z","receivedAt":"2025-01-14T11:56:18Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Hi,\n\nthis small patch series backfills in a couple of missing features into\nMeson. It also improves test coverage of our Meson-based CI jobs so that\nwe compile with Meson with Visual Studio and compile fuzzers. CI runs\nfor GitLab and GitHub can be found at [1] and [2], respectively.\n\nThe series is built on top of fbe8d3079d (Git 2.48, 2025-01-10) with\nps/meson-weak-sha1-build at 6a0ee54f9a (meson: provide a summary of\nconfigured backends, 2024-12-30) merged into it.\n\nChanges in v2:\n  - Consistently use `meson.has_header_symbol()` to fix warnings for\n    features not yet available in Meson 0.61, which is our minimum\n    required version.\n  - Add another patch that makes use use `--fatal-meson-warnings` so\n    that such warnings will cause the build to fail.\n  - Fix a bug that made GIT-VERSION-GEN always return tags as version.\n  - Adapt the approach we use to populate the project and distribution\n    tarball versions.\n  - Link to v1: https://lore.kernel.org/r/20250113-b4-pks-meson-additions-v1-0-97f6a93f691d@pks.im\n\nThanks!\n\nPatrick\n\n[1]: https://gitlab.com/gitlab-org/git/-/merge_requests/280\n[2]: https://github.com/git/git/pull/1870\n\n---\nPatrick Steinhardt (11):\n      GIT-VERSION-GEN: simplify computing the dirty marker\n      GIT-VERSION-GEN: allow running without input and output files\n      meson: populate project version via GIT-VERSION-GEN\n      meson: fix dependencies for generated headers\n      meson: wire up development environments\n      meson: wire up generation of distribution archive\n      meson: wire up fuzzers\n      meson: make the CSPRNG backend configurable\n      meson: fix compilation with Visual Studio\n      ci: raise error when Meson generates warnings\n      ci: wire up Visual Studio build with Meson\n\n .github/workflows/main.yml | 52 +++++++++++++++++++++++++++\n .gitlab-ci.yml             | 38 ++++++++++++++++++++\n GIT-VERSION-GEN            | 50 ++++++++++++++++----------\n ci/run-build-and-tests.sh  |  4 ++-\n meson.build                | 87 +++++++++++++++++++++++++++++++++++++---------\n meson_options.txt          |  4 +++\n oss-fuzz/meson.build       | 20 +++++++++++\n 7 files changed, 219 insertions(+), 36 deletions(-)\n\nRange-diff versus v1:\n\n 1:  9cceb5db4d !  1:  a546dd43be GIT-VERSION-GEN: simplify computing the dirty marker\n    @@ GIT-VERSION-GEN: then\n      \t\t\ttest -f \"$SOURCE_DIR\"/.git;\n      \t\t} &&\n     -\t\tVN=$(git -C \"$SOURCE_DIR\" describe --match \"v[0-9]*\" HEAD 2>/dev/null) &&\n    -+\t\tVN=$(git -C \"$SOURCE_DIR\" describe --match --dirty \"v[0-9]*\" 2>/dev/null) &&\n    ++\t\tVN=$(git -C \"$SOURCE_DIR\" describe --dirty --match=\"v[0-9]*\" 2>/dev/null) &&\n      \t\tcase \"$VN\" in\n      \t\t*$LF*) (exit 1) ;;\n     -\t\tv[0-9]*)\n 2:  00b9586887 <  -:  ---------- GIT-VERSION-GEN: move default version into a separate file\n -:  ---------- >  2:  3079bcc87a GIT-VERSION-GEN: allow running without input and output files\n -:  ---------- >  3:  aab1945e47 meson: populate project version via GIT-VERSION-GEN\n 3:  a7712e6874 =  4:  782b9677c3 meson: fix dependencies for generated headers\n 4:  0b30d76c7a =  5:  a9efaebe7b meson: wire up development environments\n 5:  71081feccf !  6:  92913a6b20 meson: wire up generation of distribution archive\n    @@ Metadata\n      ## Commit message ##\n         meson: wire up generation of distribution archive\n     \n    -    Meson knows to generate distribution archives via `meson dist`. Despite\n    -    generating the archive itself, this target also knows to compile and\n    -    execute tests from that archive, which helps to ensure that the result\n    -    is an adequate drop-in replacement for the versioned project.\n    +    Meson knows to generate distribution archives via `meson dist`. In\n    +    addition to generating the archive itself, this target also knows to\n    +    compile and execute tests from that archive, which helps to ensure that\n    +    the result is an adequate drop-in replacement for the versioned project.\n     \n         While this already works as-is, one omission is that we don't propagate\n         the commit that this is built from into the resulting archive. This can\n    @@ Commit message\n         version into the \"version\" file, which GIT-VERSION-GEN knows to read if\n         present.\n     \n    -    Use GIT-VERSION-GEN itself to populate that file. There are two smallish\n    -    gotchas:\n    -\n    -      - The script is executed in the build directory, not in the directory\n    -        where we generate the archive. The target directory is propagated\n    -        via the \"MESON_DIST_ROOT\" environment variable, but because we don't\n    -        use a shell to execute GIT-VERSION-GEN we cannot populate the envvar\n    -        into its arguments. We thus adapt GIT-VERSION-GEN to handle this for\n    -        us.\n    -\n    -      - We use the \"GIT-VERSION-FILE.in\" template to generate the version,\n    -        which contains a \"GIT_VERSION=\" prefix that we need to strip after\n    -        reading the \"version\" file. We could avoid this extra logic if we\n    -        used a template that only had the `@GIT_VERSION@` placeholder, but\n    -        it would require us to add one more template file.\n    +    Use GIT-VERSION-GEN to populate that file. As the script is executed in\n    +    the build directory, not in the directory where we generate the archive,\n    +    we have adapt it to honor the \"MESON_DIST_ROOT\" environment variable.\n     \n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n     \n      ## GIT-VERSION-GEN ##\n    -@@ GIT-VERSION-GEN: then\n    - \texit 1\n    - fi\n    +@@ GIT-VERSION-GEN: case \"$2\" in\n    + esac\n      \n    + OUTPUT=\"$3\"\n     +if test -n \"$OUTPUT\" && test -n \"$MESON_DIST_ROOT\"\n     +then\n     +    OUTPUT=\"$MESON_DIST_ROOT/$OUTPUT\"\n     +fi\n    -+\n    - DEF_VER=$(cat \"$SOURCE_DIR\"/GIT-VERSION)\n      \n      # Protect us from reading Git version information outside of the Git directory\n    -@@ GIT-VERSION-GEN: then\n    - \t# then try git-describe, then default.\n    - \tif test -f \"$SOURCE_DIR\"/version\n    - \tthen\n    --\t\tVN=$(cat \"$SOURCE_DIR\"/version) || VN=\"$DEF_VER\"\n    -+\t\tVN=$(cat \"$SOURCE_DIR\"/version) && VN=${VN#GIT_VERSION=} || VN=\"$DEF_VER\"\n    - \telif {\n    - \t\t\ttest -d \"$SOURCE_DIR/.git\" ||\n    - \t\t\ttest -d \"${GIT_DIR:-.git}\" ||\n    + # in case it is not a repository itself, but embedded in an unrelated\n     \n      ## meson.build ##\n     @@ meson.build: devenv.set('GIT_BUILD_DIR', meson.current_build_dir())\n    @@ meson.build: devenv.set('GIT_BUILD_DIR', meson.current_build_dir())\n     +  shell,\n     +  meson.current_source_dir() / 'GIT-VERSION-GEN',\n     +  meson.current_source_dir(),\n    -+  meson.current_source_dir() / 'GIT-VERSION-FILE.in',\n    ++  '--format=@GIT_VERSION@',\n     +  'version',\n     +)\n     +\n 6:  5dd6be9be7 =  7:  4bde8aee4c meson: wire up fuzzers\n 7:  88e2935e52 !  8:  2f33403322 meson: make the CSPRNG backend configurable\n    @@ meson.build: else\n      endif\n      \n     -if compiler.has_header_symbol('stdlib.h', 'arc4random_buf')\n    ++# Backends are ordered to reflect our preference for more secure and faster\n    ++# ones over the ones that are less so.\n     +if csprng_backend in ['auto', 'arc4random'] and compiler.has_header_symbol('stdlib.h', 'arc4random_buf', required: csprng_backend == 'arc4random')\n        libgit_c_args += '-DHAVE_ARC4RANDOM'\n     -elif compiler.has_header_symbol('bsd/stdlib.h', 'arc4random_buf')\n    @@ meson.build: else\n        libgit_c_args += '-DHAVE_ARC4RANDOM_BSD'\n     -elif compiler.has_function('getrandom', prefix: '#include <sys/random.h>')\n     +  csprng_backend = 'arc4random_bsd'\n    -+elif csprng_backend in ['auto', 'getrandom'] and compiler.has_function('getrandom', prefix: '#include <sys/random.h>', required: csprng_backend == 'getrandom')\n    ++elif csprng_backend in ['auto', 'getrandom'] and compiler.has_header_symbol('sys/random.h', 'getrandom', required: csprng_backend == 'getrandom')\n        libgit_c_args += '-DHAVE_GETRANDOM'\n     -elif compiler.has_function('getentropy', prefix: '#include <unistd.h>')\n     +  csprng_backend = 'getrandom'\n    -+elif csprng_backend in ['auto', 'getentropy'] and compiler.has_function('getentropy', prefix: '#include <unistd.h>', required: csprng_backend == 'getentropy')\n    ++elif csprng_backend in ['auto', 'getentropy'] and compiler.has_header_symbol('unistd.h', 'getentropy', required: csprng_backend == 'getentropy')\n        libgit_c_args += '-DHAVE_GETENTROPY'\n     -elif compiler.has_function('RtlGenRandom', prefix: '#include <windows.h>\\n#include <ntsecapi.h>')\n     +  csprng_backend = 'getentropy'\n    -+elif csprng_backend in ['auto', 'rtlgenrandom'] and compiler.has_function('RtlGenRandom', prefix: '#include <windows.h>\\n#include <ntsecapi.h>', required: csprng_backend == 'rtlgenrandom')\n    ++elif csprng_backend in ['auto', 'rtlgenrandom'] and compiler.has_header_symbol('ntsecapi.h', 'RtlGenRandom', prefix: '#include <windows.h>', required: csprng_backend == 'rtlgenrandom')\n        libgit_c_args += '-DHAVE_RTLGENRANDOM'\n     -elif openssl.found()\n     +  csprng_backend = 'rtlgenrandom'\n 8:  f6ee13d6dc <  -:  ---------- meson: fix compilation with Visual Studio\n -:  ---------- >  9:  d56a24e15a meson: fix compilation with Visual Studio\n -:  ---------- > 10:  c624f1d554 ci: raise error when Meson generates warnings\n 9:  946c31f452 = 11:  c7f7e2309a ci: wire up Visual Studio build with Meson\n\n---\nbase-commit: 35a417ddf0eab983e4d5eb69e628aa198114bb05\nchange-id: 20250107-b4-pks-meson-additions-055c16b3052b\n\n"},{"id":"510496","messageId":"20250114-b4-pks-meson-additions-v2-1-8d7ec676cfd9@pks.im","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-0-8d7ec676cfd9@pks.im","subject":"[PATCH v2 01/11] GIT-VERSION-GEN: simplify computing the dirty marker","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-01-14T11:56:11Z","receivedAt":"2025-01-14T11:56:19Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The GIT-VERSION-GEN script computes the version that Git is being built\nfrom. When building from a commit with an unclean worktree it knows to\nappend \"-dirty\" to that version to indicate that there were custom\nchanges applied and that it isn't the exact same as that commit.\n\nThe dirtiness check is done manually via git-diff-index(1), which is\nsomewhat puzzling though: we already use git-describe(1) to compute the\nversion, which also knows to compute dirtiness via the \"--dirty\" flag.\nBut digging back in history explains why: the \"-dirty\" suffix was added\nin 31e0b2ca81 (GIT 1.5.4.3, 2008-02-23), and git-describe(1) didn't yet\nhave support for \"--dirty\" back then.\n\nRefactor the script to use git-describe(1). Despite being simpler, it\nalso results in a small speedup:\n\n    Benchmark 1: git describe --dirty --match \"v[0-9]*\"\n      Time (mean ± σ):      12.5 ms ±   0.3 ms    [User: 6.3 ms, System: 8.8 ms]\n      Range (min … max):    12.0 ms …  13.5 ms    200 runs\n\n    Benchmark 2: git describe --match \"v[0-9]*\" HEAD && git update-index -q --refresh && git diff-index --name-only HEAD --\n      Time (mean ± σ):      17.9 ms ±   1.1 ms    [User: 8.8 ms, System: 14.4 ms]\n      Range (min … max):    17.0 ms …  30.6 ms    148 runs\n\n    Summary\n      git describe --dirty --match \"v[0-9]*\" ran\n        1.43 ± 0.09 times faster than git describe --match \"v[0-9]*\" && git update-index -q --refresh && git diff-index --name-only HEAD --\n\nWhile the speedup doesn't really matter on Unix-based systems, where\nfilesystem operations are typically fast, they do matter on Windows\nwhere the commands take a couple hundred milliseconds. A quick and dirty\ncheck on that system shows a speedup from ~800ms to ~400ms.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n GIT-VERSION-GEN | 6 +-----\n 1 file changed, 1 insertion(+), 5 deletions(-)\n\ndiff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN\nindex f2af817feaeb384dee0ffd197f02a31cf2d31f87..b8b683b9337e5771e14a2cfb84022a11489bb432 100755\n--- a/GIT-VERSION-GEN\n+++ b/GIT-VERSION-GEN\n@@ -39,13 +39,9 @@ then\n \t\t\ttest -d \"${GIT_DIR:-.git}\" ||\n \t\t\ttest -f \"$SOURCE_DIR\"/.git;\n \t\t} &&\n-\t\tVN=$(git -C \"$SOURCE_DIR\" describe --match \"v[0-9]*\" HEAD 2>/dev/null) &&\n+\t\tVN=$(git -C \"$SOURCE_DIR\" describe --dirty --match=\"v[0-9]*\" 2>/dev/null) &&\n \t\tcase \"$VN\" in\n \t\t*$LF*) (exit 1) ;;\n-\t\tv[0-9]*)\n-\t\t\tgit -C \"$SOURCE_DIR\" update-index -q --refresh\n-\t\t\ttest -z \"$(git -C \"$SOURCE_DIR\" diff-index --name-only HEAD --)\" ||\n-\t\t\tVN=\"$VN-dirty\" ;;\n \t\tesac\n \tthen\n \t\tVN=$(echo \"$VN\" | sed -e 's/-/./g');\n\n-- \n2.48.0.257.gd3603152ad.dirty\n\n"},{"id":"510498","messageId":"20250114-b4-pks-meson-additions-v2-2-8d7ec676cfd9@pks.im","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-0-8d7ec676cfd9@pks.im","subject":"[PATCH v2 02/11] GIT-VERSION-GEN: allow running without input and output files","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-01-14T11:56:12Z","receivedAt":"2025-01-14T11:56:20Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The GIT-VERSION-GEN script requires an input file containing formatting\ndirectives to be replaced as well as an output file that will get\noverwritten in case the file contents have changed. When computing the\nproject version for Meson we don't want to have either though:\n\n  - We only want to compute the version without anything else, but don't\n    have an input file that would match that exact format. While we\n    could of course introduce a new file just for that usecase, it feels\n    suboptimal to add another file every time we want to have a slightly\n    different format for versioned data.\n\n  - The computed version needs to be read from stdout so that Meson can\n    wire it up for the project.\n\nExtend the script to handle both usecases by recognizing `--format=` as\nalternative to providing an input path and by writing to stdout in case\nno output file was given.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n GIT-VERSION-GEN | 44 +++++++++++++++++++++++++++++---------------\n 1 file changed, 29 insertions(+), 15 deletions(-)\n\ndiff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN\nindex b8b683b9337e5771e14a2cfb84022a11489bb432..9d201a98fd2766911544225c62159cbfe8dff5fe 100755\n--- a/GIT-VERSION-GEN\n+++ b/GIT-VERSION-GEN\n@@ -5,21 +5,29 @@ DEF_VER=v2.48.0\n LF='\n '\n \n-if test \"$#\" -ne 3\n+if test \"$#\" -lt 2 || test \"$#\" -gt 3\n then\n-    echo >&2 \"USAGE: $0 <SOURCE_DIR> <INPUT> <OUTPUT>\"\n+    echo >&2 \"USAGE: $0 <SOURCE_DIR> (--format=<STRING>|<INPUT>) [<OUTPUT>]\"\n     exit 1\n fi\n \n SOURCE_DIR=\"$1\"\n-INPUT=\"$2\"\n-OUTPUT=\"$3\"\n \n-if ! test -f \"$INPUT\"\n-then\n-\techo >&2 \"Input is not a file: $INPUT\"\n-\texit 1\n-fi\n+case \"$2\" in\n+--format=*)\n+\tINPUT=\"${2#--format=}\"\n+\t;;\n+*)\n+\tif ! test -f \"$2\"\n+\tthen\n+\t\techo >&2 \"Input is not a file: $2\"\n+\t\texit 1\n+\tfi\n+\tINPUT=$(cat \"$2\")\n+\t;;\n+esac\n+\n+OUTPUT=\"$3\"\n \n # Protect us from reading Git version information outside of the Git directory\n # in case it is not a repository itself, but embedded in an unrelated\n@@ -74,19 +82,25 @@ read GIT_MAJOR_VERSION GIT_MINOR_VERSION GIT_MICRO_VERSION GIT_PATCH_LEVEL trail\n $(echo \"$GIT_VERSION\" 0 0 0 0 | tr '.a-zA-Z-' ' ')\n EOF\n \n-sed -e \"s|@GIT_VERSION@|$GIT_VERSION|\" \\\n+REPLACED=$(printf \"%s\" \"$INPUT\" | sed -e \"s|@GIT_VERSION@|$GIT_VERSION|\" \\\n \t-e \"s|@GIT_MAJOR_VERSION@|$GIT_MAJOR_VERSION|\" \\\n \t-e \"s|@GIT_MINOR_VERSION@|$GIT_MINOR_VERSION|\" \\\n \t-e \"s|@GIT_MICRO_VERSION@|$GIT_MICRO_VERSION|\" \\\n \t-e \"s|@GIT_PATCH_LEVEL@|$GIT_PATCH_LEVEL|\" \\\n \t-e \"s|@GIT_BUILT_FROM_COMMIT@|$GIT_BUILT_FROM_COMMIT|\" \\\n \t-e \"s|@GIT_USER_AGENT@|$GIT_USER_AGENT|\" \\\n-\t-e \"s|@GIT_DATE@|$GIT_DATE|\" \\\n-\t\"$INPUT\" >\"$OUTPUT\".$$+\n+\t-e \"s|@GIT_DATE@|$GIT_DATE|\"\n+)\n \n-if ! test -f \"$OUTPUT\" || ! cmp \"$OUTPUT\".$$+ \"$OUTPUT\" >/dev/null\n+if test -z \"$OUTPUT\"\n then\n-\tmv \"$OUTPUT\".$$+ \"$OUTPUT\"\n+\tprintf \"%s\\n\" \"$REPLACED\"\n else\n-\trm \"$OUTPUT\".$$+\n+\tprintf \"%s\\n\" \"$REPLACED\" >\"$OUTPUT\".$$+\n+\tif ! test -f \"$OUTPUT\" || ! cmp \"$OUTPUT\".$$+ \"$OUTPUT\" >/dev/null\n+\tthen\n+\t\tmv \"$OUTPUT\".$$+ \"$OUTPUT\"\n+\telse\n+\t\trm \"$OUTPUT\".$$+\n+\tfi\n fi\n\n-- \n2.48.0.257.gd3603152ad.dirty\n\n"},{"id":"510499","messageId":"20250114-b4-pks-meson-additions-v2-3-8d7ec676cfd9@pks.im","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-0-8d7ec676cfd9@pks.im","subject":"[PATCH v2 03/11] meson: populate project version via GIT-VERSION-GEN","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-01-14T11:56:13Z","receivedAt":"2025-01-14T11:56:20Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The Git version for Meson is currently wired up manually. It can thus\ngrow (and alread has grown) stale quite easily, as having multiple\nsources of truth is never a good idea. This issue is mostly of cosmetic\nnature as we don't use the project version anywhere, and instead use the\nGIT-VERSION-GEN script to propagate the correct version into our build.\nBut it is somewhat puzzling when `meson setup` announces to build an old\nGit release.\n\nThere are a couple of alternatives for how to solve this:\n\n  - We can keep the version undefined, but this makes Meson output\n    \"undefined\" for the version, as well.\n\n  - We can use GIT-VERSION-GEN to generate the version for us. At the\n    point of configuring the project we haven't yet figured out host\n    details though, and thus we didn't yet set up the shell environment.\n    While not an issue for Unix-based systems, this would be an issue in\n    Windows, where the shell typically gets provided via Git for Windows\n    and thus requires some special setup.\n\n  - We can pull the default version out of GIT-VERSION-GEN and move it\n    into its own file. This likely requires some adjustments for scripts\n    that bump the version, but allows Meson to read the version from\n    that file trivially.\n\nPick the second option and use GIT-VERSION-GEN as it gives us the most\naccurate version. In order to fix the bootstrapping issue on Windows\nsystems we simply set the version to 'unknown' in case no shell was\nfound. As the version is only of cosmetic value this isn't really much\nof an issue.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build | 9 ++++++++-\n 1 file changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/meson.build b/meson.build\nindex 7361eb2eaad422e7a6c6ed95d275615836c21cdb..213998986e8942cee080fc5b9b675860cf429ecc 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -170,7 +170,14 @@\n \n project('git', 'c',\n   meson_version: '>=0.61.0',\n-  version: 'v2.47.GIT',\n+  # The version is only of cosmetic nature, so if we cannot find a shell yet we\n+  # simply don't set up a version at all. This may be the case for example on\n+  # Windows systems, where we first have to bootstrap the host environment.\n+  version: find_program('sh', required: false).found() ? run_command(\n+    'GIT-VERSION-GEN', meson.current_source_dir(), '--format=@GIT_VERSION@',\n+    capture: true,\n+    check: true,\n+  ).stdout().strip() : 'unknown',\n )\n \n fs = import('fs')\n\n-- \n2.48.0.257.gd3603152ad.dirty\n\n"},{"id":"510500","messageId":"20250114-b4-pks-meson-additions-v2-4-8d7ec676cfd9@pks.im","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-0-8d7ec676cfd9@pks.im","subject":"[PATCH v2 04/11] meson: fix dependencies for generated headers","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-01-14T11:56:14Z","receivedAt":"2025-01-14T11:56:21Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We generate a couple of headers from our documentation. These headers\nare added to the libgit sources, but two of them aren't used by the\nlibrary, but instead by our builtins. This can cause parallel builds to\nfail because the builtin object may be compiled before the header was\ngenerated.\n\nFix the issue by adding both \"config-list.h\" and \"hook-list.h\" to the\nlist of builtin sources. While \"command-list.h\" is generated similarly,\nit is used by \"help.c\" and thus part of the libgit sources indeed.\n\nReported-by: Evan Martin <evan.martin@gmail.com>\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build | 18 +++++++++---------\n 1 file changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/meson.build b/meson.build\nindex 213998986e8942cee080fc5b9b675860cf429ecc..4053024dadeb0aafc067784b976ed3bd96171181 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -487,6 +487,13 @@ libgit_sources = [\n   'xdiff/xutils.c',\n ]\n \n+libgit_sources += custom_target(\n+  input: 'command-list.txt',\n+  output: 'command-list.h',\n+  command: [shell, meson.current_source_dir() + '/generate-cmdlist.sh', meson.current_source_dir(), '@OUTPUT@'],\n+  env: script_environment,\n+)\n+\n builtin_sources = [\n   'builtin/add.c',\n   'builtin/am.c',\n@@ -614,14 +621,7 @@ builtin_sources = [\n   'builtin/write-tree.c',\n ]\n \n-libgit_sources += custom_target(\n-  input: 'command-list.txt',\n-  output: 'command-list.h',\n-  command: [shell, meson.current_source_dir() + '/generate-cmdlist.sh', meson.current_source_dir(), '@OUTPUT@'],\n-  env: script_environment,\n-)\n-\n-libgit_sources += custom_target(\n+builtin_sources += custom_target(\n   output: 'config-list.h',\n   command: [\n     shell,\n@@ -632,7 +632,7 @@ libgit_sources += custom_target(\n   env: script_environment,\n )\n \n-libgit_sources += custom_target(\n+builtin_sources += custom_target(\n   input: 'Documentation/githooks.txt',\n   output: 'hook-list.h',\n   command: [\n\n-- \n2.48.0.257.gd3603152ad.dirty\n\n"},{"id":"510501","messageId":"20250114-b4-pks-meson-additions-v2-5-8d7ec676cfd9@pks.im","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-0-8d7ec676cfd9@pks.im","subject":"[PATCH v2 05/11] meson: wire up development environments","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-01-14T11:56:15Z","receivedAt":"2025-01-14T11:56:21Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The Meson build system is able to wire up development environments. The\nintent is to make build artifacts of the project available. This is\ntypically used to export e.g. paths to linkable libraries, which isn't\nall that interesting in our context given that we don't have an official\nlibrary interface.\n\nBut what we can use this mechanism for is to expose the built Git\nexecutables as well as the build directory. This allows users to play\naround with the built Git version in the devenv, and allows them to\nexecute our test scripts directly with the built distribution.\n\nWire up this feature, which can then be used via `meson devenv` in the\nbuild directory.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build | 8 ++++++++\n 1 file changed, 8 insertions(+)\n\ndiff --git a/meson.build b/meson.build\nindex 4053024dadeb0aafc067784b976ed3bd96171181..ab4f229436d3070de692a24c3a196a79d214b46f 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -1939,6 +1939,14 @@ configure_file(\n   configuration: build_options_config,\n )\n \n+# Development environments can be used via `meson devenv -C <builddir>`. This\n+# allows you to execute test scripts directly with the built Git version and\n+# puts the built version of Git in your PATH.\n+devenv = environment()\n+devenv.set('GIT_BUILD_DIR', meson.current_build_dir())\n+devenv.prepend('PATH', meson.current_build_dir() / 'bin-wrappers')\n+meson.add_devenv(devenv)\n+\n summary({\n   'curl': curl.found(),\n   'expat': expat.found(),\n\n-- \n2.48.0.257.gd3603152ad.dirty\n\n"},{"id":"510502","messageId":"20250114-b4-pks-meson-additions-v2-6-8d7ec676cfd9@pks.im","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-0-8d7ec676cfd9@pks.im","subject":"[PATCH v2 06/11] meson: wire up generation of distribution archive","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-01-14T11:56:16Z","receivedAt":"2025-01-14T11:56:22Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Meson knows to generate distribution archives via `meson dist`. In\naddition to generating the archive itself, this target also knows to\ncompile and execute tests from that archive, which helps to ensure that\nthe result is an adequate drop-in replacement for the versioned project.\n\nWhile this already works as-is, one omission is that we don't propagate\nthe commit that this is built from into the resulting archive. This can\nbe fixed though by adding a distribution script that propagates the\nversion into the \"version\" file, which GIT-VERSION-GEN knows to read if\npresent.\n\nUse GIT-VERSION-GEN to populate that file. As the script is executed in\nthe build directory, not in the directory where we generate the archive,\nwe have adapt it to honor the \"MESON_DIST_ROOT\" environment variable.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n GIT-VERSION-GEN |  4 ++++\n meson.build     | 12 ++++++++++++\n 2 files changed, 16 insertions(+)\n\ndiff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN\nindex 9d201a98fd2766911544225c62159cbfe8dff5fe..f6764555ce6fd46ca4ddbaebb3b48809707e60f8 100755\n--- a/GIT-VERSION-GEN\n+++ b/GIT-VERSION-GEN\n@@ -28,6 +28,10 @@ case \"$2\" in\n esac\n \n OUTPUT=\"$3\"\n+if test -n \"$OUTPUT\" && test -n \"$MESON_DIST_ROOT\"\n+then\n+    OUTPUT=\"$MESON_DIST_ROOT/$OUTPUT\"\n+fi\n \n # Protect us from reading Git version information outside of the Git directory\n # in case it is not a repository itself, but embedded in an unrelated\ndiff --git a/meson.build b/meson.build\nindex ab4f229436d3070de692a24c3a196a79d214b46f..5d074134195e5689d08da5597f0859d9623d014e 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -1947,6 +1947,18 @@ devenv.set('GIT_BUILD_DIR', meson.current_build_dir())\n devenv.prepend('PATH', meson.current_build_dir() / 'bin-wrappers')\n meson.add_devenv(devenv)\n \n+# Generate the 'version' file in the distribution tarball. This is used via\n+# `meson dist -C <builddir>` to populate the source archive with the Git\n+# version that the archive is being generated from. GIT-VERSION-GEN knows to\n+# pick up this file.\n+meson.add_dist_script(\n+  shell,\n+  meson.current_source_dir() / 'GIT-VERSION-GEN',\n+  meson.current_source_dir(),\n+  '--format=@GIT_VERSION@',\n+  'version',\n+)\n+\n summary({\n   'curl': curl.found(),\n   'expat': expat.found(),\n\n-- \n2.48.0.257.gd3603152ad.dirty\n\n"},{"id":"510503","messageId":"20250114-b4-pks-meson-additions-v2-7-8d7ec676cfd9@pks.im","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-0-8d7ec676cfd9@pks.im","subject":"[PATCH v2 07/11] meson: wire up fuzzers","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-01-14T11:56:17Z","receivedAt":"2025-01-14T11:56:22Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Meson does not yet know to build our fuzzers. Introduce a new build\noption \"fuzzers\" and wire up the fuzzers in case it is enabled. Adapt\nour CI jobs so that they build the fuzzers by default.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n ci/run-build-and-tests.sh |  3 ++-\n meson.build               |  4 ++++\n meson_options.txt         |  2 ++\n oss-fuzz/meson.build      | 20 ++++++++++++++++++++\n 4 files changed, 28 insertions(+), 1 deletion(-)\n\ndiff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh\nindex 76667a1277720d74e09e8da227b5e0832003e0e2..6c828c3b755153dab179f73346e7124bda49c90e 100755\n--- a/ci/run-build-and-tests.sh\n+++ b/ci/run-build-and-tests.sh\n@@ -53,7 +53,8 @@ case \"$jobname\" in\n *-meson)\n \tgroup \"Configure\" meson setup build . \\\n \t\t--warnlevel 2 --werror \\\n-\t\t--wrap-mode nofallback\n+\t\t--wrap-mode nofallback \\\n+\t\t-Dfuzzers=true\n \tgroup \"Build\" meson compile -C build --\n \tif test -n \"$run_tests\"\n \tthen\ndiff --git a/meson.build b/meson.build\nindex 5d074134195e5689d08da5597f0859d9623d014e..95baada74af8f7731867e7075d9986b32a034ff4 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -1906,6 +1906,10 @@ if get_option('tests')\n   subdir('t')\n endif\n \n+if get_option('fuzzers')\n+  subdir('oss-fuzz')\n+endif\n+\n subdir('bin-wrappers')\n if get_option('docs') != []\n   subdir('Documentation')\ndiff --git a/meson_options.txt b/meson_options.txt\nindex 89b01bad042b533b23e0e2b4b780ce152ee688c8..34ba679cf931b67a794a9bb7e765bfb22106381e 100644\n--- a/meson_options.txt\n+++ b/meson_options.txt\n@@ -95,3 +95,5 @@ option('tests', type: 'boolean', value: true,\n   description: 'Enable building tests. This requires Perl, but is separate from the \"perl\" option such that you can build tests without Perl features enabled.')\n option('test_output_directory', type: 'string',\n   description: 'Path to the directory used to store test outputs')\n+option('fuzzers', type: 'boolean', value: false,\n+  description: 'Enable building fuzzers.')\ndiff --git a/oss-fuzz/meson.build b/oss-fuzz/meson.build\nnew file mode 100644\nindex 0000000000000000000000000000000000000000..ed79665501655eae4948623c07114fab23a55393\n--- /dev/null\n+++ b/oss-fuzz/meson.build\n@@ -0,0 +1,20 @@\n+fuzz_programs = [\n+  'fuzz-commit-graph.c',\n+  'fuzz-config.c',\n+  'fuzz-credential-from-url-gently.c',\n+  'fuzz-date.c',\n+  'fuzz-pack-headers.c',\n+  'fuzz-pack-idx.c',\n+  'fuzz-parse-attr-line.c',\n+  'fuzz-url-decode-mem.c',\n+]\n+\n+foreach fuzz_program : fuzz_programs\n+  executable(fs.stem(fuzz_program),\n+    sources: [\n+      'dummy-cmd-main.c',\n+      fuzz_program,\n+    ],\n+    dependencies: [libgit, common_main],\n+  )\n+endforeach\n\n-- \n2.48.0.257.gd3603152ad.dirty\n\n"},{"id":"510504","messageId":"20250114-b4-pks-meson-additions-v2-8-8d7ec676cfd9@pks.im","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-0-8d7ec676cfd9@pks.im","subject":"[PATCH v2 08/11] meson: make the CSPRNG backend configurable","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-01-14T11:56:18Z","receivedAt":"2025-01-14T11:56:22Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The CSPRNG backend is not configurable in Meson and isn't quite\ndiscoverable, either. Make it configurable and add the actual backend\nused to the summary.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build       | 28 +++++++++++++++++++++-------\n meson_options.txt |  2 ++\n 2 files changed, 23 insertions(+), 7 deletions(-)\n\ndiff --git a/meson.build b/meson.build\nindex 95baada74af8f7731867e7075d9986b32a034ff4..e50ccac5c9f6d310d8c9f83d893ea802b5827252 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -1332,6 +1332,7 @@ if not meson.is_cross_build() and fs.exists('/dev/tty')\n   libgit_c_args += '-DHAVE_DEV_TTY'\n endif\n \n+csprng_backend = get_option('csprng_backend')\n https_backend = get_option('https_backend')\n sha1_backend = get_option('sha1_backend')\n sha1_unsafe_backend = get_option('sha1_unsafe_backend')\n@@ -1343,7 +1344,7 @@ if https_backend == 'auto' and security_framework.found()\n   https_backend = 'CommonCrypto'\n endif\n \n-openssl_required = 'openssl' in [https_backend, sha1_backend, sha1_unsafe_backend, sha256_backend]\n+openssl_required = 'openssl' in [csprng_backend, https_backend, sha1_backend, sha1_unsafe_backend, sha256_backend]\n openssl = dependency('openssl', required: openssl_required, default_options: ['default_library=static'])\n if https_backend == 'auto' and openssl.found()\n   https_backend = 'openssl'\n@@ -1428,18 +1429,30 @@ else\n   error('Unhandled SHA256 backend ' + sha256_backend)\n endif\n \n-if compiler.has_header_symbol('stdlib.h', 'arc4random_buf')\n+# Backends are ordered to reflect our preference for more secure and faster\n+# ones over the ones that are less so.\n+if csprng_backend in ['auto', 'arc4random'] and compiler.has_header_symbol('stdlib.h', 'arc4random_buf', required: csprng_backend == 'arc4random')\n   libgit_c_args += '-DHAVE_ARC4RANDOM'\n-elif compiler.has_header_symbol('bsd/stdlib.h', 'arc4random_buf')\n+  csprng_backend = 'arc4random'\n+elif csprng_backend in ['auto', 'arc4random_bsd'] and compiler.has_header_symbol('bsd/stdlib.h', 'arc4random_buf', required: csprng_backend == 'arc4random_bsd')\n   libgit_c_args += '-DHAVE_ARC4RANDOM_BSD'\n-elif compiler.has_function('getrandom', prefix: '#include <sys/random.h>')\n+  csprng_backend = 'arc4random_bsd'\n+elif csprng_backend in ['auto', 'getrandom'] and compiler.has_header_symbol('sys/random.h', 'getrandom', required: csprng_backend == 'getrandom')\n   libgit_c_args += '-DHAVE_GETRANDOM'\n-elif compiler.has_function('getentropy', prefix: '#include <unistd.h>')\n+  csprng_backend = 'getrandom'\n+elif csprng_backend in ['auto', 'getentropy'] and compiler.has_header_symbol('unistd.h', 'getentropy', required: csprng_backend == 'getentropy')\n   libgit_c_args += '-DHAVE_GETENTROPY'\n-elif compiler.has_function('RtlGenRandom', prefix: '#include <windows.h>\\n#include <ntsecapi.h>')\n+  csprng_backend = 'getentropy'\n+elif csprng_backend in ['auto', 'rtlgenrandom'] and compiler.has_header_symbol('ntsecapi.h', 'RtlGenRandom', prefix: '#include <windows.h>', required: csprng_backend == 'rtlgenrandom')\n   libgit_c_args += '-DHAVE_RTLGENRANDOM'\n-elif openssl.found()\n+  csprng_backend = 'rtlgenrandom'\n+elif csprng_backend in ['auto', 'openssl'] and openssl.found()\n   libgit_c_args += '-DHAVE_OPENSSL_CSPRNG'\n+  csprng_backend = 'openssl'\n+elif csprng_backend in ['auto', 'urandom']\n+  csprng_backend = 'urandom'\n+else\n+  error('Unsupported CSPRNG backend: ' + csprng_backend)\n endif\n \n if get_option('runtime_prefix')\n@@ -1976,6 +1989,7 @@ summary({\n }, section: 'Auto-detected features')\n \n summary({\n+  'csprng': csprng_backend,\n   'https': https_backend,\n   'sha1': sha1_backend,\n   'sha1_unsafe': sha1_unsafe_backend,\ndiff --git a/meson_options.txt b/meson_options.txt\nindex 34ba679cf931b67a794a9bb7e765bfb22106381e..5429022f30621105cd6974e4260cca60e5f24324 100644\n--- a/meson_options.txt\n+++ b/meson_options.txt\n@@ -47,6 +47,8 @@ option('regex', type: 'feature', value: 'auto',\n   description: 'Use the system-provided regex library instead of the bundled one.')\n \n # Backends.\n+option('csprng_backend', type: 'combo', value: 'auto', choices: ['auto', 'arc4random', 'arc4random_bsd', 'getrandom', 'getentropy', 'rtlgenrandom', 'openssl', 'urandom'],\n+  description: 'The backend to use for generating cryptographically-secure pseudo-random numbers.')\n option('https_backend', type: 'combo', value: 'auto', choices: ['auto', 'openssl', 'CommonCrypto', 'none'],\n   description: 'The HTTPS backend to use when connecting to remotes.')\n option('sha1_backend', type: 'combo', choices: ['openssl', 'block', 'sha1dc', 'CommonCrypto'], value: 'sha1dc',\n\n-- \n2.48.0.257.gd3603152ad.dirty\n\n"},{"id":"510505","messageId":"20250114-b4-pks-meson-additions-v2-9-8d7ec676cfd9@pks.im","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-0-8d7ec676cfd9@pks.im","subject":"[PATCH v2 09/11] meson: fix compilation with Visual Studio","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-01-14T11:56:19Z","receivedAt":"2025-01-14T11:56:23Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The Visual Studio compiler defaults to C89 unless explicitly asked to\nuse a different version of the C standard. We don't specify any C\nstandard at all though in our Meson build, and consequently compiling\nGit fails:\n\n    ...\\git\\git-compat-util.h(14): fatal error C1189: #error:  \"Required C99 support is in a test phase.  Please see git-compat-util.h for more details.\"\n\nFix the issue by specifying the project's C standard. Funny enough,\nspecifying C99 does not work because apparently, `__STDC_VERSION__` is\nnot getting defined in that version at all. Instead, we have to specify\nC11 as the project's C standard, which is also done in our CMake build\ninstructions.\n\nWe don't want to generally enforce C11 though, as our requiremets only\nstate that a C99 compiler is required. In fact, we don't even require\nplain C99, but rather the GNU variant thereof.\n\nMeson allows us to handle this case rather easily by specifying\n\"gnu99,c11\", which will cause it to fall back to C11 in case GNU C99 is\nunsupported. This feature has only been introduced with Meson 1.3.0\nthough, and we support 0.61.0 and newer. In case we use such an oldish\nversion though we fall back to requiring GNU99 unconditionally. This\nmeans that Windows essentially requires Meson 1.3.0 and newer when using\nVisual Studio, but I doubt that this is ever going to be a real problem.\n\nTested-by: M Hickford <mirth.hickford@gmail.com>\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build | 8 ++++++++\n 1 file changed, 8 insertions(+)\n\ndiff --git a/meson.build b/meson.build\nindex e50ccac5c9f6d310d8c9f83d893ea802b5827252..30d7a894904dfe86bedb2a7a8de25529502403e5 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -178,6 +178,14 @@ project('git', 'c',\n     capture: true,\n     check: true,\n   ).stdout().strip() : 'unknown',\n+  default_options: [\n+    # Git requires C99 with GNU extensions, which of course isn't supported by\n+    # MSVC. Funny enough, C99 doesn't work with MSVC either, as it has only\n+    # learned to define __STDC_VERSION__ with C11 and later. We thus require\n+    # GNU C99 and fall back to C11. Meson only learned to handle the fallback\n+    # with version 1.3.0, so on older versions we use GNU C99 unconditionally.\n+    'c_std=' + (meson.version().version_compare('>=1.3.0') ? 'gnu99,c11' : 'gnu99'),\n+  ],\n )\n \n fs = import('fs')\n\n-- \n2.48.0.257.gd3603152ad.dirty\n\n"},{"id":"510506","messageId":"20250114-b4-pks-meson-additions-v2-10-8d7ec676cfd9@pks.im","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-0-8d7ec676cfd9@pks.im","subject":"[PATCH v2 10/11] ci: raise error when Meson generates warnings","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-01-14T11:56:20Z","receivedAt":"2025-01-14T11:56:24Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Meson prints warnings in several cases, like for example when using a\nfeature supported by the current version of Meson, but not yet supported\nby the minimum required version as declared by the project. These\nwarnings will not cause the setup to fail by default, which makes it\nquite easy to miss them.\n\nImprove this by passing `--fatal-meson-warnings` to `meson setup` so\nthat our CI jobs will fail on warnings.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n ci/run-build-and-tests.sh | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh\nindex 6c828c3b755153dab179f73346e7124bda49c90e..964322055f5db0eae0c794b543664e24ae4249f7 100755\n--- a/ci/run-build-and-tests.sh\n+++ b/ci/run-build-and-tests.sh\n@@ -52,6 +52,7 @@ esac\n case \"$jobname\" in\n *-meson)\n \tgroup \"Configure\" meson setup build . \\\n+\t\t--fatal-meson-warnings \\\n \t\t--warnlevel 2 --werror \\\n \t\t--wrap-mode nofallback \\\n \t\t-Dfuzzers=true\n\n-- \n2.48.0.257.gd3603152ad.dirty\n\n"},{"id":"510507","messageId":"20250114-b4-pks-meson-additions-v2-11-8d7ec676cfd9@pks.im","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-0-8d7ec676cfd9@pks.im","subject":"[PATCH v2 11/11] ci: wire up Visual Studio build with Meson","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-01-14T11:56:21Z","receivedAt":"2025-01-14T11:56:24Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Add a new job to GitHub Actions and GitLab CI that builds and tests\nMeson-based builds with Visual Studio.\n\nA couple notes:\n\n  - While the build job is mandatory, the test job is marked as \"manual\"\n    on GitLab so that it doesn't run by default. We already have a bunch\n    of Windows-based jobs, and the computational overhead that these\n    cause is simply out of proportion to run the test suite twice.\n\n    The same isn't true for GitHub as I could not find a way to make a\n    subset of jobs manually triggered.\n\n  - We disable Perl. This is because we pick up Perl from Git for\n    Windows, which outputs different paths (\"/c/\" instead of \"C:\\\") than\n    what we expect in our tests.\n\n  - We don't use the Git for Windows SDK. Instead, the build only\n    depends on Visual Studio, Meson and Git for Windows. All the other\n    dependencies like curl, pcre2 and zlib get pulled in and compiled\n    automatically by Meson and thus do not have to be provided by the\n    system.\n\n  - We open-code \"ci/run-test-slice.sh\". This is because we only have\n    direct access to PowerShell, so we manually implement the logic.\n    There is an upstream pull request for the Meson build system [1] to\n    implement test slicing in Meson directly.\n\n  - We don't process test artifacts for failed CI jobs. This is done to\n    keep down prerequisites to a minimum.\n\nAll tests are passing.\n\n[1]: https://github.com/mesonbuild/meson/pull/14092\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n .github/workflows/main.yml | 52 ++++++++++++++++++++++++++++++++++++++++++++++\n .gitlab-ci.yml             | 38 +++++++++++++++++++++++++++++++++\n 2 files changed, 90 insertions(+)\n\ndiff --git a/.github/workflows/main.yml b/.github/workflows/main.yml\nindex 900be9957a23fcaa64e1aefd0c8638c5f84b7997..7f55f8b3a91d6caf95934af308a2bd35a19a62f1 100644\n--- a/.github/workflows/main.yml\n+++ b/.github/workflows/main.yml\n@@ -248,6 +248,58 @@ jobs:\n       with:\n         name: failed-tests-windows-vs-${{ matrix.nr }}\n         path: ${{env.FAILED_TEST_ARTIFACTS}}\n+\n+  windows-meson-build:\n+    name: win+Meson build\n+    needs: ci-config\n+    if: needs.ci-config.outputs.enabled == 'yes'\n+    runs-on: windows-latest\n+    concurrency:\n+      group: windows-meson-build-${{ github.ref }}\n+      cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}\n+    steps:\n+    - uses: actions/checkout@v4\n+    - uses: actions/setup-python@v5\n+    - name: Set up dependencies\n+      shell: pwsh\n+      run: pip install meson ninja\n+    - name: Setup\n+      shell: pwsh\n+      run: meson setup build -Dperl=disabled\n+    - name: Compile\n+      shell: pwsh\n+      run: meson compile -C build\n+    - name: Upload build artifacts\n+      uses: actions/upload-artifact@v4\n+      with:\n+        name: windows-meson-artifacts\n+        path: build\n+  windows-meson-test:\n+    name: win+Meson test\n+    runs-on: windows-latest\n+    needs: [ci-config, windows-meson-build]\n+    strategy:\n+      fail-fast: false\n+      matrix:\n+        nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n+    concurrency:\n+      group: windows-meson-test-${{ matrix.nr }}-${{ github.ref }}\n+      cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}\n+    steps:\n+    - uses: actions/checkout@v4\n+    - uses: actions/setup-python@v5\n+    - name: Set up dependencies\n+      shell: pwsh\n+      run: pip install meson ninja\n+    - name: Download build artifacts\n+      uses: actions/download-artifact@v4\n+      with:\n+        name: windows-meson-artifacts\n+        path: build\n+    - name: Test\n+      shell: pwsh\n+      run: meson test -C build --list | Select-Object -Skip 1 | Select-String .* | Group-Object -Property { $_.LineNumber % 10 } | Where-Object Name -EQ ${{ matrix.nr }} | ForEach-Object { meson test -C build --no-rebuild --print-errorlogs $_.Group }\n+\n   regular:\n     name: ${{matrix.vector.jobname}} (${{matrix.vector.pool}})\n     needs: ci-config\ndiff --git a/.gitlab-ci.yml b/.gitlab-ci.yml\nindex 9254e01583306e67dc12b6b9e0015183e1108655..4976e18a0503298f38230f5ba7348675baf48664 100644\n--- a/.gitlab-ci.yml\n+++ b/.gitlab-ci.yml\n@@ -149,6 +149,44 @@ test:mingw64:\n     - git-sdk/usr/bin/bash.exe -l -c 'ci/print-test-failures.sh'\n   parallel: 10\n \n+.msvc-meson:\n+  tags:\n+    - saas-windows-medium-amd64\n+  before_script:\n+    - choco install -y git meson ninja openssl\n+    - Import-Module $env:ChocolateyInstall\\helpers\\chocolateyProfile.psm1\n+    - refreshenv\n+    # The certificate store for Python on Windows is broken and fails to fetch\n+    # certificates, see https://bugs.python.org/issue36011. This seems to\n+    # mostly be an issue with how the GitLab image is set up as it is a\n+    # non-issue on GitHub Actions. Work around the issue by importing\n+    # cetrificates manually.\n+    - Invoke-WebRequest https://curl.haxx.se/ca/cacert.pem -OutFile cacert.pem\n+    - openssl pkcs12 -export -nokeys -in cacert.pem -out certs.pfx -passout \"pass:\"\n+    - Import-PfxCertificate -CertStoreLocation Cert:\\LocalMachine\\Root -FilePath certs.pfx\n+\n+build:msvc-meson:\n+  extends: .msvc-meson\n+  stage: build\n+  script:\n+    - meson setup build -Dperl=disabled\n+    - meson compile -C build\n+  artifacts:\n+    paths:\n+      - build\n+\n+test:msvc-meson:\n+  extends: .msvc-meson\n+  stage: test\n+  when: manual\n+  timeout: 6h\n+  needs:\n+    - job: \"build:msvc-meson\"\n+      artifacts: true\n+  script:\n+    - meson test -C build --list | Select-Object -Skip 1 | Select-String .* | Group-Object -Property { $_.LineNumber % $Env:CI_NODE_TOTAL + 1 } | Where-Object Name -EQ $Env:CI_NODE_INDEX | ForEach-Object { meson test -C build --no-rebuild --print-errorlogs $_.Group }\n+  parallel: 10\n+\n test:fuzz-smoke-tests:\n   image: ubuntu:latest\n   stage: test\n\n-- \n2.48.0.257.gd3603152ad.dirty\n\n"},{"id":"510528","messageId":"xmqqplkp47b4.fsf@gitster.g","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-0-8d7ec676cfd9@pks.im","subject":"Re: [PATCH v2 00/11] meson: a couple of additions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-01-14T17:46:39Z","receivedAt":"2025-01-14T17:46:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n>      -\t\tVN=$(git -C \"$SOURCE_DIR\" describe --match \"v[0-9]*\" HEAD 2>/dev/null) &&\n>     -+\t\tVN=$(git -C \"$SOURCE_DIR\" describe --match --dirty \"v[0-9]*\" 2>/dev/null) &&\n>     ++\t\tVN=$(git -C \"$SOURCE_DIR\" describe --dirty --match=\"v[0-9]*\" 2>/dev/null) &&\n\nAhh, you only said \"found the issue\" and it was building suspense\n;-)\n\nIt turns out that I wasn't affected while testing because my build\ninfrastructure around \"make\" computes the version string by itself\nindependently from what \"make/GIT-VERSION-GEN\" does, and stuffs it\nin the 'version' file, before running \"make install\".  And that is\nwhy I didn't notice the breakage before Ramsay reported X-<.\n\nThis fix looks obviously good.\n\nThanks.\n"},{"id":"510998","messageId":"87plkgibr0.fsf@iotcl.com","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-6-8d7ec676cfd9@pks.im","subject":"Re: [PATCH v2 06/11] meson: wire up generation of distribution archive","fromName":"Toon Claes","fromEmail":"toon@iotcl.com","sentAt":"2025-01-21T12:37:23Z","receivedAt":"2025-01-21T12:37:37Z","isPatch":true,"sender":{"key":"toon@iotcl.com","avatar":"https://avatars.githubusercontent.com/u/121621?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> Meson knows to generate distribution archives via `meson dist`. In\n> addition to generating the archive itself, this target also knows to\n> compile and execute tests from that archive, which helps to ensure that\n> the result is an adequate drop-in replacement for the versioned project.\n>\n> While this already works as-is, one omission is that we don't propagate\n> the commit that this is built from into the resulting archive. This can\n> be fixed though by adding a distribution script that propagates the\n> version into the \"version\" file, which GIT-VERSION-GEN knows to read if\n> present.\n>\n> Use GIT-VERSION-GEN to populate that file. As the script is executed in\n> the build directory, not in the directory where we generate the archive,\n> we have adapt it to honor the \"MESON_DIST_ROOT\" environment variable.\n\nI failed to understand why you couldn't pass the absolute path of the\noutput file to GIT-VERSION-GEN. So I looked at the previous version of\nthis patch, and it seems you explain better over there.\n\nI was testing things locally and tried this line for the last argument\nto the script:\n\n  run_command(shell, '-c', 'echo $MESON_DIST_ROOT', capture: true, check: true).stdout().strip() / 'version',\n\nAnd I think I understand it better now. Meson does not execute this when\nyou run `meson dist`, but when it (re)generates it's build files. At\nthat stage $MESON_DIST_ROOT is not set.\n\nIt's unfortunate we have to learn GIT-VERSION-GEN about the\n$MESON_DIST_ROOT environment variable, but I don't see any other way.\n\n\n--\nToon\n"},{"id":"510999","messageId":"87msfkiaqa.fsf@iotcl.com","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-10-8d7ec676cfd9@pks.im","subject":"Re: [PATCH v2 10/11] ci: raise error when Meson generates warnings","fromName":"Toon Claes","fromEmail":"toon@iotcl.com","sentAt":"2025-01-21T12:59:25Z","receivedAt":"2025-01-21T12:59:36Z","isPatch":true,"sender":{"key":"toon@iotcl.com","avatar":"https://avatars.githubusercontent.com/u/121621?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> Meson prints warnings in several cases, like for example when using a\n> feature supported by the current version of Meson, but not yet supported\n> by the minimum required version as declared by the project. These\n> warnings will not cause the setup to fail by default, which makes it\n> quite easy to miss them.\n>\n> Improve this by passing `--fatal-meson-warnings` to `meson setup` so\n> that our CI jobs will fail on warnings.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  ci/run-build-and-tests.sh | 1 +\n>  1 file changed, 1 insertion(+)\n>\n> diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh\n> index 6c828c3b755153dab179f73346e7124bda49c90e..964322055f5db0eae0c794b543664e24ae4249f7 100755\n> --- a/ci/run-build-and-tests.sh\n> +++ b/ci/run-build-and-tests.sh\n> @@ -52,6 +52,7 @@ esac\n>  case \"$jobname\" in\n>  *-meson)\n>  \tgroup \"Configure\" meson setup build . \\\n> +\t\t--fatal-meson-warnings \\\n>  \t\t--warnlevel 2 --werror \\\n>  \t\t--wrap-mode nofallback \\\n>  \t\t-Dfuzzers=true\n>\n> -- \n> 2.48.0.257.gd3603152ad.dirty\n\nCool, this would have caught me trying to use `fs.copyfile`:\n\n    $ meson setup build --fatal-meson-warnings\n\n    # ... [snip] ...\n\n    ../meson.build:1466: WARNING: Project targets '>=0.61.0' but uses feature introduced in '0.64.0': fs.copyfile.\n\n    ../meson.build:1466:3: ERROR: Fatal warnings enabled, aborting\n\n\n(I missed that warning)\n\n--\nToon\n\n"},{"id":"511000","messageId":"87ldv4ia2v.fsf@iotcl.com","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-3-8d7ec676cfd9@pks.im","subject":"Re: [PATCH v2 03/11] meson: populate project version via GIT-VERSION-GEN","fromName":"Toon Claes","fromEmail":"toon@iotcl.com","sentAt":"2025-01-21T13:13:28Z","receivedAt":"2025-01-21T13:13:47Z","isPatch":true,"sender":{"key":"toon@iotcl.com","avatar":"https://avatars.githubusercontent.com/u/121621?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> The Git version for Meson is currently wired up manually. It can thus\n> grow (and alread has grown) stale quite easily, as having multiple\n\nSmall typo: alread -> already\n\n\n-- \nToon\n\n"},{"id":"511001","messageId":"87jzaoi9yc.fsf@iotcl.com","threadId":"62804","inReplyTo":"20250114-b4-pks-meson-additions-v2-2-8d7ec676cfd9@pks.im","subject":"Re: [PATCH v2 02/11] GIT-VERSION-GEN: allow running without input and output files","fromName":"Toon Claes","fromEmail":"toon@iotcl.com","sentAt":"2025-01-21T13:16:11Z","receivedAt":"2025-01-21T13:16:26Z","isPatch":true,"sender":{"key":"toon@iotcl.com","avatar":"https://avatars.githubusercontent.com/u/121621?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> The GIT-VERSION-GEN script requires an input file containing formatting\n> directives to be replaced as well as an output file that will get\n> overwritten in case the file contents have changed. When computing the\n> project version for Meson we don't want to have either though:\n>\n>   - We only want to compute the version without anything else, but don't\n>     have an input file that would match that exact format. While we\n>     could of course introduce a new file just for that usecase, it feels\n>     suboptimal to add another file every time we want to have a slightly\n>     different format for versioned data.\n>\n>   - The computed version needs to be read from stdout so that Meson can\n>     wire it up for the project.\n>\n> Extend the script to handle both usecases by recognizing `--format=` as\n> alternative to providing an input path and by writing to stdout in case\n> no output file was given.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  GIT-VERSION-GEN | 44 +++++++++++++++++++++++++++++---------------\n>  1 file changed, 29 insertions(+), 15 deletions(-)\n>\n> diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN\n> index b8b683b9337e5771e14a2cfb84022a11489bb432..9d201a98fd2766911544225c62159cbfe8dff5fe 100755\n> --- a/GIT-VERSION-GEN\n> +++ b/GIT-VERSION-GEN\n> @@ -5,21 +5,29 @@ DEF_VER=v2.48.0\n>  LF='\n>  '\n>  \n> -if test \"$#\" -ne 3\n> +if test \"$#\" -lt 2 || test \"$#\" -gt 3\n>  then\n> -    echo >&2 \"USAGE: $0 <SOURCE_DIR> <INPUT> <OUTPUT>\"\n> +    echo >&2 \"USAGE: $0 <SOURCE_DIR> (--format=<STRING>|<INPUT>) [<OUTPUT>]\"\n>      exit 1\n>  fi\n>  \n>  SOURCE_DIR=\"$1\"\n> -INPUT=\"$2\"\n> -OUTPUT=\"$3\"\n>  \n> -if ! test -f \"$INPUT\"\n> -then\n> -\techo >&2 \"Input is not a file: $INPUT\"\n> -\texit 1\n> -fi\n> +case \"$2\" in\n> +--format=*)\n> +\tINPUT=\"${2#--format=}\"\n> +\t;;\n> +*)\n> +\tif ! test -f \"$2\"\n> +\tthen\n> +\t\techo >&2 \"Input is not a file: $2\"\n> +\t\texit 1\n> +\tfi\n> +\tINPUT=$(cat \"$2\")\n> +\t;;\n> +esac\n> +\n> +OUTPUT=\"$3\"\n>  \n>  # Protect us from reading Git version information outside of the Git directory\n>  # in case it is not a repository itself, but embedded in an unrelated\n> @@ -74,19 +82,25 @@ read GIT_MAJOR_VERSION GIT_MINOR_VERSION GIT_MICRO_VERSION GIT_PATCH_LEVEL trail\n>  $(echo \"$GIT_VERSION\" 0 0 0 0 | tr '.a-zA-Z-' ' ')\n>  EOF\n>  \n> -sed -e \"s|@GIT_VERSION@|$GIT_VERSION|\" \\\n> +REPLACED=$(printf \"%s\" \"$INPUT\" | sed -e \"s|@GIT_VERSION@|$GIT_VERSION|\" \\\n>  \t-e \"s|@GIT_MAJOR_VERSION@|$GIT_MAJOR_VERSION|\" \\\n>  \t-e \"s|@GIT_MINOR_VERSION@|$GIT_MINOR_VERSION|\" \\\n>  \t-e \"s|@GIT_MICRO_VERSION@|$GIT_MICRO_VERSION|\" \\\n>  \t-e \"s|@GIT_PATCH_LEVEL@|$GIT_PATCH_LEVEL|\" \\\n>  \t-e \"s|@GIT_BUILT_FROM_COMMIT@|$GIT_BUILT_FROM_COMMIT|\" \\\n>  \t-e \"s|@GIT_USER_AGENT@|$GIT_USER_AGENT|\" \\\n> -\t-e \"s|@GIT_DATE@|$GIT_DATE|\" \\\n> -\t\"$INPUT\" >\"$OUTPUT\".$$+\n> +\t-e \"s|@GIT_DATE@|$GIT_DATE|\"\n> +)\n>  \n> -if ! test -f \"$OUTPUT\" || ! cmp \"$OUTPUT\".$$+ \"$OUTPUT\" >/dev/null\n> +if test -z \"$OUTPUT\"\n>  then\n> -\tmv \"$OUTPUT\".$$+ \"$OUTPUT\"\n> +\tprintf \"%s\\n\" \"$REPLACED\"\n>  else\n> -\trm \"$OUTPUT\".$$+\n> +\tprintf \"%s\\n\" \"$REPLACED\" >\"$OUTPUT\".$$+\n> +\tif ! test -f \"$OUTPUT\" || ! cmp \"$OUTPUT\".$$+ \"$OUTPUT\" >/dev/null\n> +\tthen\n> +\t\tmv \"$OUTPUT\".$$+ \"$OUTPUT\"\n> +\telse\n> +\t\trm \"$OUTPUT\".$$+\n> +\tfi\n>  fi\n>\n> -- \n> 2.48.0.257.gd3603152ad.dirty\n\nI was considering to suggest to have GIT-VERSION-GEN accept --stdin for\n$INPUT and have it read from stdin instead of passing the format as an\nargument, but looking at the following commits I agree with your\napproach.\n\n--\nToon\n"},{"id":"511057","messageId":"Z5De75u-TpwmUpZ7@pks.im","threadId":"62804","inReplyTo":"87plkgibr0.fsf@iotcl.com","subject":"Re: [PATCH v2 06/11] meson: wire up generation of distribution archive","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-01-22T12:05:03Z","receivedAt":"2025-01-22T12:05:09Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Jan 21, 2025 at 01:37:23PM +0100, Toon Claes wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> > Meson knows to generate distribution archives via `meson dist`. In\n> > addition to generating the archive itself, this target also knows to\n> > compile and execute tests from that archive, which helps to ensure that\n> > the result is an adequate drop-in replacement for the versioned project.\n> >\n> > While this already works as-is, one omission is that we don't propagate\n> > the commit that this is built from into the resulting archive. This can\n> > be fixed though by adding a distribution script that propagates the\n> > version into the \"version\" file, which GIT-VERSION-GEN knows to read if\n> > present.\n> >\n> > Use GIT-VERSION-GEN to populate that file. As the script is executed in\n> > the build directory, not in the directory where we generate the archive,\n> > we have adapt it to honor the \"MESON_DIST_ROOT\" environment variable.\n> \n> I failed to understand why you couldn't pass the absolute path of the\n> output file to GIT-VERSION-GEN. So I looked at the previous version of\n> this patch, and it seems you explain better over there.\n> \n> I was testing things locally and tried this line for the last argument\n> to the script:\n> \n>   run_command(shell, '-c', 'echo $MESON_DIST_ROOT', capture: true, check: true).stdout().strip() / 'version',\n> \n> And I think I understand it better now. Meson does not execute this when\n> you run `meson dist`, but when it (re)generates it's build files. At\n> that stage $MESON_DIST_ROOT is not set.\n> \n> It's unfortunate we have to learn GIT-VERSION-GEN about the\n> $MESON_DIST_ROOT environment variable, but I don't see any other way.\n\nHm. Thinking about it a bit more there is an alternative:\n\n    meson.add_dist_script(\n      shell,\n      '-c',\n      '\"$1\" \"$2\" \"$3\" --format=\"@GIT_VERSION@\" \"$MESON_DIST_ROOT/version\"',\n      'GIT-VERSION-GEN',\n      shell,\n      meson.current_source_dir() / 'GIT-VERSION-GEN',\n      meson.current_source_dir(),\n    )\n\nI think this is a much better solution as it doesn't require us to teach\nthe script about `MESON_DIST_ROOT`.\n\nPatrick\n"}]}