Repository: mesonbuild/meson

Issue:
0.54.1 regression for Fortran generated library()
**Describe the bug**
Commit bd8d079473d introduced the Meson 0.54.1 regression for library() created from Fortran generated source files.
This regression happens for "static" or "shared" library().

---

With Windows 10 and Gfortran 10.1.0:

The "good" Meson 0.54.0 command line is:

```sh
gfortran "-Imod3@sha" "-I." "-I.." "-fdiagnostics-color=always" "-pipe" "-Wall" "-g" "-Jmod3@sha" -o mod3@sha/mod3.f90.obj -c "C:/Users/code/temp/7 generated/build/mod3.f90"
```

The "bad" Meson 0.54.1 command line is:

```sh
gfortran "-Imod3@sha" "-I." "-I.." "-fdiagnostics-color=always" "-pipe" "-Wall" "-g" "-Jmod3@sha" -o "C:_Users_code_temp_7 generated_build_mod3.f90.obj" -c "C:/Users/code/temp/7 generated/build/mod3.f90"
```

--- 

On Ubuntu 20.04 with Gfortran 9.3.0 or Gfortran 10.0.1 the regression is **not** apparent.

Meson 0.54.0 emits:

```sh
gfortran -Imod3@sha -I. -I.. -fdiagnostics-color=always -pipe -Wall -g -D_FILE_OFFSET_BITS=64 -fPIC -Jmod3@sha -o 'mod3@sha/mod3.f90.o' -c '/mnt/c/Users/code/temp/7 generated/build/mod3.f90'
```

Meson 0.54.1 emits:
```sh
 gfortran -Imod3@sha -I. -I.. -fdiagnostics-color=always -pipe -Wall -g -D_FILE_OFFSET_BITS=64 -fPIC -Jmod3@sha -o 'mod3@sha/_mnt_c_Users_code_temp_7 generated_build_mod3.f90.o' -c '/mnt/c/Users/code/temp/7 generated/build/mod3.f90'
```

**To Reproduce**
I updated the Meson project test "test cases/fortran/7 generated" in PR #7266 as this is an important case to test.

**Expected behavior**
A clear and concise description of what you expected to happen.

**system parameters**

The broken setup is:

* Gfortran 10.1.0 (MinGW via MSYS2)
* native build
* Windows 10
* Python: 3.7.7
* Meson: 0.54.1 introduced the regression
* Ninja: 1.10.0

A **working** setup is:

* Gfortran 9.3.0 or Gfortran 10.0.1
* native build
* Ubuntu 20.04 (Windows Subsystem for Linux)
* Python: 3.7.7
* Meson: 0.54.1 or master (not broken like Windows MinGW)
* Ninja: 1.10.0


Discussion:

Resolving patch:
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -501,6 +501,12 @@ def determine_rpath_dirs(self, target):
         target.rpath_dirs_to_remove.update([d.encode('utf8') for d in result])
         return tuple(result)
 
+    @staticmethod
+    def canonicalize_filename(fname):
+        for ch in ('/', '\\', ':'):
+            fname = fname.replace(ch, '_')
+        return fname
+
     def object_filename_from_source(self, target, source):
         assert isinstance(source, mesonlib.File)
         build_dir = self.environment.get_build_dir()
@@ -531,7 +537,7 @@ def object_filename_from_source(self, target, source):
                 source = os.path.relpath(os.path.join(build_dir, rel_src),
                                          os.path.join(self.environment.get_source_dir(), target.get_subdir()))
         machine = self.environment.machines[target.for_machine]
-        return source.replace('/', '_').replace('\\', '_') + '.' + machine.get_object_suffix()
+        return self.canonicalize_filename(source) + '.' + machine.get_object_suffix()
 
     def determine_ext_objs(self, extobj, proj_dir_to_build_root):
         result = []
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -2160,7 +2160,7 @@ def generate_llvm_ir_compile(self, target, src):
             src_filename = os.path.basename(src)
         else:
             src_filename = src
-        obj_basename = src_filename.replace('/', '_').replace('\\', '_')
+        obj_basename = self.canonicalize_filename(src_filename)
         rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename)
         rel_obj += '.' + self.environment.machines[target.for_machine].get_object_suffix()
         commands += self.get_compile_debugfile_args(compiler, target, rel_obj)


Test patch:
diff --git a/test cases/fortran/7 generated/meson.build b/test cases/fortran/7 generated/meson.build
--- a/test cases/fortran/7 generated/meson.build	
+++ b/test cases/fortran/7 generated/meson.build	
@@ -6,6 +6,13 @@ project('generated', 'fortran')
 conf_data = configuration_data()
 conf_data.set('ONE', 1)
 conf_data.set('TWO', 2)
+conf_data.set('THREE', 3)
+
+outfile = configure_file(
+      input : 'mod3.fpp', output : 'mod3.f90', configuration : conf_data)
+# Manually build absolute path to source file to test
+# https://github.com/mesonbuild/meson/issues/7265
+three = library('mod3', meson.current_build_dir() / 'mod3.f90')
 
 templates_basenames = ['mod2', 'mod1']
 generated_sources = []
@@ -18,5 +25,5 @@ foreach template_basename : templates_basenames
 endforeach
 
 sources = ['prog.f90'] + generated_sources
-exe = executable('generated', sources)
+exe = executable('generated', sources, link_with: three)
 test('generated', exe)
diff --git a/test cases/fortran/7 generated/mod1.fpp b/test cases/fortran/7 generated/mod1.fpp
--- a/test cases/fortran/7 generated/mod1.fpp	
+++ b/test cases/fortran/7 generated/mod1.fpp	
@@ -1,6 +1,6 @@
 module mod1
-  implicit none
+implicit none
 
-  integer, parameter :: modval1 = @ONE@
+integer, parameter :: modval1 = @ONE@
 
 end module mod1
diff --git a/test cases/fortran/7 generated/mod2.fpp b/test cases/fortran/7 generated/mod2.fpp
--- a/test cases/fortran/7 generated/mod2.fpp	
+++ b/test cases/fortran/7 generated/mod2.fpp	
@@ -1,7 +1,7 @@
 module mod2
-  use mod1
-  implicit none
+use mod1, only : modval1
+implicit none
 
-  integer, parameter :: modval2 = @TWO@
+integer, parameter :: modval2 = @TWO@
 
 end module mod2
diff --git a/test cases/fortran/7 generated/mod3.fpp b/test cases/fortran/7 generated/mod3.fpp
new file mode 100644
--- /dev/null
+++ b/test cases/fortran/7 generated/mod3.fpp	
@@ -0,0 +1,6 @@
+module mod3
+implicit none
+
+integer, parameter :: modval3 = @THREE@
+
+end module mod3
diff --git a/test cases/fortran/7 generated/prog.f90 b/test cases/fortran/7 generated/prog.f90
--- a/test cases/fortran/7 generated/prog.f90	
+++ b/test cases/fortran/7 generated/prog.f90	
@@ -1,7 +1,8 @@
-program prog
-use mod2
+program generated
+use mod2, only : modval1, modval2
+use mod3, only : modval3
 implicit none
 
-if (modval1 + modval2 /= 3) stop 1
+if (modval1 + modval2 + modval3 /= 6) error stop
 
-end program prog
+end program generated