Subject: Re: [PATCH] meson: ensure correct version-def.h is used

From: Patrick Steinhardt <[email-masked]>
Date: Mon, 13 Jan 2025 11:50:13 +0100

On Mon, Jan 13, 2025 at 11:28:04AM +0100, Toon Claes wrote:
> To build the libgit-version library, Meson first generates
> `version-def.h` in the build directory. Then it compiles `version.c`
> into a library. During compilation, Meson tells to include both the
> build directory and the project root directory.
> 
> However, when the user previously has compiled Git using Make, they will
> have a `version-def.h` file in project root directory as well. Because
> `version-def.h` is included in `version.c` using the #include directive
> with double quotes, some compilers will look for the header file in the
> same directory as the source file. This will cause compilation of
> `version.c` ran by Meson to include `version-def.h` previously made by
> Make, which might be out of date.

Makes sense.

> Copy `version.c` to the build directory before compiling it to ensure
> `version-def.h` from the build directory is used.

I was wondering whether there were other solutions that are a bit
less intricate. One was to include <version-def.h> instead and then play
around with include directories, but that feels even more fragile than
the proposed solution.

Another alternative would be to inject the full path to the generated
header file. For example something like this:

diff --git a/meson.build b/meson.build
index 3e31648dc1..dbe6e7651f 100644
--- a/meson.build
+++ b/meson.build
@@ -1543,7 +1543,9 @@ libgit_version_library = static_library('git-version',
     'version.c',
     version_def_h,
   ],
-  c_args: libgit_c_args,
+  c_args: libgit_c_args + [
+    '-DGIT_VERSION_H="' + version_def_h.full_path() + '"',
+  ],
   dependencies: libgit_dependencies,
   include_directories: libgit_include_directories,
 )
diff --git a/version.c b/version.c
index 4d763ab48d..4786c4e0a5 100644
--- a/version.c
+++ b/version.c
@@ -1,8 +1,13 @@
 #include "git-compat-util.h"
 #include "version.h"
-#include "version-def.h"
 #include "strbuf.h"
 
+#ifndef GIT_VERSION_H
+# include "version-def.h"
+#else
+# include GIT_VERSION_H
+#endif
+
 const char git_version_string[] = GIT_VERSION;
 const char git_built_from_commit_string[] = GIT_BUILT_FROM_COMMIT;

This feels least fragile and isn't adding a lot of complexity, either.

> diff --git a/meson.build b/meson.build
> index 0064eb64f546a6349a8694ce251bd352febda6fe..8ecb22c80e4fc3f194e97c14dbf83f541d72b25b 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -1486,11 +1486,15 @@ version_def_h = custom_target(
>    env: version_gen_environment,
>  )
>  
> +# Because most compilers prefer header files in the same directory as the source
> +# file, copy version.c to the build directory.
> +version_c = fs.copyfile(meson.current_source_dir() / 'version.c', 'version.c')

Unfortunately, `fs.copyfile()` is not supported in Meson v0.61 yet,
which is our minimum required version of Meson. You can use a custom
target with cp(1) though. I have a patch series pending that starts to
generate errors in our CI when warnings are printed to catch such issues
going forward.

Patrick