Repository: mesonbuild/meson

Issue:
test cases/rust/13 external c dependencies fails on Solaris due to lack of static zlib
**Describe the bug**
When running the tests on Solaris 11.4, the runs of `test cases/rust/13 external c dependencies` with `-Dstatic=true` incorrectly report that libz.a is found, and then fail when ninja calls gcc for the linking step because Solaris only packages libz.so, and not libz.a.

**To Reproduce**
(in a checked out copy of this repo on Solaris 11.4)
```
cd test\ cases/rust/13\ external\ c\ dependencies/
env PKG_CONFIG_PATH=/usr/lib/64/pkgconfig python3 ../../../meson.py setup --wipe builddir -Dmethod=system -Dstatic=true
cd builddir/
ninja
```
or with `-Dmethod` set to `pkg-config` instead of `system`

When using `-Dmethod=pkg-config` it even correctly output a warning that this wouldn't work, but continued to try anyway:
```
WARNING: Static library 'z' not found for dependency 'zlib', may not be statically linked
```

**Expected behavior**
I expected the `if not dep_zlib.found()` clause in [meson.build](https://github.com/mesonbuild/meson/blob/0.63.3/test%20cases/rust/13%20external%20c%20dependencies/meson.build#L8) to trigger the `'MESON_SKIP_TEST: Could not find a @0@ zlib'.format(get_option('static') ? 'static' : 'shared')` message and exit.

**system parameters**
* native build
* Oracle Solaris 11.4
* Python 3.7.13
* meson 0.63.3
* 1.11.0




Discussion:
@alanc seems like the best course of action is to skip the test on Solaris. Care to submit a PR? grep for `MESON_SKIP_TEST` I believe for other usages
We could do that, though the test passes for much of the matrix - in our Solaris package, we've only disabled the static linking portion of the test matrix, though in a way that isn't suitable for upstream:
https://github.com/mesonbuild/meson/blob/master/mesonbuild/linkers/linkers.py#L210

But it seems that's just ignoring an actual bug in meson in which `dependency('zlib', static : true, ...)` is  claiming the static library is available when it's not, but I don't know where in meson to fix that.
@alanc you should be able to look at the $builddir/meson-log/meson-log.txt and see more detailed debug information on why meson thinks it can find a static zlib. But this seems to be a common problem
Okay, so I ran `../../../meson.py setup builddir -Dstatic=true -Dmethod=system` in `test cases/rust/13 external c dependencies` and it ran okay and didn't trigger the `if not dep_zlib.found()` check in `meson.build`, but running ninja to complete the build failed with:
```
1/1] Compiling Rust source ../prog.rs
FAILED: prog 
rustc -C linker=gcc --color=always --crate-type bin -g --crate-name prog --emit dep-info=prog.d --emit link -o prog -l static=c_accessing_zlib -l static=z -L . ../prog.rs
error: linking with `gcc` failed: exit status: 1
  |
  = note: "gcc" "-m64" "prog.prog.6eac67e5-cgu.0.rcgu.o" "prog.prog.6eac67e5-cgu.1.rcgu.o" "prog.prog.6eac67e5-cgu.2.rcgu.o" "prog.prog.6eac67e5-cgu.3.rcgu.o" "prog.prog.6eac67e5-cgu.4.rcgu.o" "prog.prog.6eac67e5-cgu.5.rcgu.o" "prog.prog.6eac67e5-cgu.6.rcgu.o" "prog.4uosbuk8q2vxpxvl.rcgu.o" "-Wl,-z,ignore" "-L" "." "-L" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib" "-Wl,-Bstatic" "-lc_accessing_zlib" "-lz" "-Wl,--start-group" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libstd-448b0ec7735498fd.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libpanic_unwind-cf7840f652e1e74b.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libobject-a415004c6305c80a.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libmemchr-852e1db29e8b47d7.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libaddr2line-d2df1dc6066e7e6b.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libgimli-58f21fcc219ab3ed.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/librustc_demangle-1ec9b4a3a790749c.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libstd_detect-50aac8de7c8e2b18.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libhashbrown-f2b26a599e83e61d.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libminiz_oxide-e8f9f2e4ded3d663.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libadler-ca5a986d2200bea1.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/librustc_std_workspace_alloc-24acd48a0c30e202.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libunwind-4526533112008efc.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libcfg_if-33198cecd6457e3e.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/liblibc-6a900d3212994ec6.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/liballoc-2708c1d1ddec5df8.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/librustc_std_workspace_core-2627cd144f4b48b5.rlib" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libcore-bea228e8c308139a.rlib" "-Wl,--end-group" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib/libcompiler_builtins-9d6a34782d7fc5aa.rlib" "-Wl,-Bdynamic" "-lsocket" "-lposix4" "-lpthread" "-lresolv" "-lgcc_s" "-lc" "-lm" "-lrt" "-lpthread" "-L" "/usr/lib/amd64/rustlib/x86_64-pc-solaris/lib" "-o" "prog" "-nodefaultlibs"
  = note: ld: fatal: library -lz: not found
          collect2: error: ld returned 1 exit status
          

error: aborting due to previous error

ninja: build stopped: subcommand failed.
```

The test results in `meson-logs/meson-log.txt` aren't clearly labeled, but I think the test in question reported:
```
Rust compiler for the build machine: rustc -C linker=gcc (rustc 1.61.0-dev)
Rust linker for the build machine: rustc -C linker=gcc ld.solaris 5.11-1.3274
Build machine cpu family: x86_64
Build machine cpu: x86_64
Host machine cpu family: x86_64
Host machine cpu: x86_64
Target machine cpu family: x86_64
Target machine cpu: x86_64
Running compile:
Working directory:  /export/alanc/git/github/meson/test cases/rust/13 external c
 dependencies/builddir/meson-private/tmpy8jn7h0l
Command line:  gcc /export/alanc/git/github/meson/test cases/rust/13 external c dependencies/builddir/meson-private/tmpy8jn7h0l/testfile.c -o /export/alanc/git/github/meson/test cases/rust/13 external c dependencies/builddir/meson-private/tmpy8jn7h0l/output.exe -D_FILE_OFFSET_BITS=64 -O0 -Wl,--start-group -lz -Wl,--end-group -z nodefs 

Code:
 int main(void) { return 0; }

Compiler stdout:
 
Compiler stderr:

```

Notably, unlike the build-time failure, that test doesn't report passing any "-Wl,-Bstatic" flag to determine if it can statically link with -lz.

Using the classic method of "grep and copy" programming, without actually understanding the source code, this small change to `ZlibSystemDependency` seems to fix it:

```
--- a/mesonbuild/dependencies/dev.py
+++ b/mesonbuild/dependencies/dev.py
@@ -509,7 +509,7 @@ class ZlibSystemDependency(SystemDependency):
             else:
                 libs = ['z']
             for lib in libs:
-                l = self.clib_compiler.find_library(lib, environment, [])
+                l = self.clib_compiler.find_library(lib, environment, [], self.libtype)
                 h = self.clib_compiler.has_header('zlib.h', '', environment, dependencies=[self])
                 if l and h[0]:
                     self.is_found = True
```

With that, running `../../../meson.py setup builddir -Dstatic=true -Dmethod=system` results in:
```
Run-time dependency zlib found: NO (tried system)

meson.build:9:2: ERROR: Problem encountered: MESON_SKIP_TEST: Could not find a static zlib
```
while it still completes setup & build successfully with `-Dstatic=false`.
Since no one said my fix looked wrong or made a better suggestion in the past 4 months I submitted pull request #11569 for this change.

On Solaris 11.4.57, this changes the results of that rust test case from:
```
 [SUCCESS]   rust: 13 external c dependencies    (static=False method=cmake)
 [SUCCESS]   rust: 13 external c dependencies    (static=False method=pkg-config)
 [SUCCESS]   rust: 13 external c dependencies    (static=False method=system)
 [SUCCESS]   rust: 13 external c dependencies    (static=True method=cmake)
  [ERROR]    rust: 13 external c dependencies    (static=True method=system)
During: build
Reason: Compiling source code failed.
```
to
```
 [SUCCESS]   rust: 13 external c dependencies    (static=False method=cmake)
 [SUCCESS]   rust: 13 external c dependencies    (static=False method=pkg-config)
 [SUCCESS]   rust: 13 external c dependencies    (static=False method=system)
 [SUCCESS]   rust: 13 external c dependencies    (static=True method=cmake)
 [SKIPPED]   rust: 13 external c dependencies    (static=True method=system)
Reason: Could not find a static zlib
```

Resolving patch:
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -2090,13 +2090,14 @@ def generate_rust_target(self, target: build.BuildTarget) -> None:
                 if a in rustc.native_static_libs:
                     # Exclude link args that rustc already add by default
                     continue
-                if a.endswith(('.dll', '.so', '.dylib')):
+                if a.endswith(('.dll', '.so', '.dylib', '.a', '.lib')):
                     dir_, lib = os.path.split(a)
                     linkdirs.add(dir_)
                     lib, ext = os.path.splitext(lib)
                     if lib.startswith('lib'):
                         lib = lib[3:]
-                    args.extend(['-l', f'dylib={lib}'])
+                    _type = 'static' if a.endswith(('.a', '.lib')) else 'dylib'
+                    args.extend(['-l', f'{_type}={lib}'])
                 elif a.startswith('-L'):
                     args.append(a)
                 elif a.startswith('-l'):
diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py
--- a/mesonbuild/dependencies/dev.py
+++ b/mesonbuild/dependencies/dev.py
@@ -536,7 +536,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.
             else:
                 libs = ['z']
             for lib in libs:
-                l = self.clib_compiler.find_library(lib, environment, [])
+                l = self.clib_compiler.find_library(lib, environment, [], self.libtype)
                 h = self.clib_compiler.has_header('zlib.h', '', environment, dependencies=[self])
                 if l and h[0]:
                     self.is_found = True


Test patch: