From: Eric Pouech eric.pouech@gmail.com
When doing a parallel build on multi-arch tree, it sometimes generates errors like: /usr/lib/gcc/x86_64-w64-mingw32/12.2.1/../../../../x86_64-w64-mingw32/bin/ld: cannot find authz.dll-63db5999.spec.o: Aucun fichier ou dossier de ce type
I added a couple of traces, showing that the two winegcc invocations for linking the DLL on the two arch:s are run in parallel *BUT* end up with the same output file. The one generated from tools.h / make_temp_file() called in winegcc{build_spec_obj()}.
build_spec_obj() invokes 'winebuild -o XXX.spec.o' that starts (in -o option handling) by unlinking XXXX.spec.o.
This opens a race condition on the output file name: 1) the XXX.spec.o is chosen by first arch in winegcc 2) XXX.spec.o is unlinked in winebuild (for first arch) 3) XXX.spec.o is chosen by second arch in winegcc 4) both winebuild invocations (first & second arch) now write to the same file
In a nutshell, make_temp_file() isn't sufficient to ensure unicity of filename when such filename is erased (even briefly) in the build process.
Proposed workaround: - use target name in generation of .spec.o filename to avoid collision.
There's might other areas which could suffer from same kind of issue. Alternative options: - explicitly insert getpid() or target_alias in generated name in make_temp_file() - change value in make_temp_file (using time(NULL) + getpid() in parallel build can generate rather likely the same value in two consecutive processes) time(NULL) ^ getpid() might generate less collisions (even if it doesn't eradicate them). - change winebuild not to unlink output file but rather use open(O_TRUNC) (didn't look into it)
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- tools/winegcc/winegcc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 142ab81de12..8103e45115c 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -1000,6 +1000,7 @@ static const char *build_spec_obj( struct options *opts, const char *spec_file, struct strarray spec_args = get_winebuild_args( opts ); struct strarray tool; const char *spec_o_name, *output_name; + char *target_name;
/* get the filename from the path */ output_name = get_basename( output_file ); @@ -1012,7 +1013,9 @@ static const char *build_spec_obj( struct options *opts, const char *spec_file, strarray_add( &spec_args, strmake( "--ld-cmd=%s", strarray_tostring( tool, " " ))); }
- spec_o_name = get_temp_file(output_name, ".spec.o"); + target_name = strmake("%s%s", output_name, opts->target_alias); + spec_o_name = get_temp_file(target_name, ".spec.o"); + free(target_name); if (!is_pe) { if (opts->pic) strarray_add(&spec_args, "-fPIC");