Repository: conan-io/conan

Issue:
[bug] incorrect paths generated by pkgconfigdeps.py when using --deployer option
### Incorrect path generated by PkgConfigDeps when using --deployer option

OS and Connan Version Information:
OS: Mac Sonama
Conan version 2.4.1


### How to reproduce it

1. Create a `conanfile.txt` with a couple of packages; shouldn't matter what these packages are as long as they are available in the central registry; here is the file contents I used:
```ini
[requires]
  libuv/1.48.0
  uvw/3.4.0

[generators]
PkgConfigDeps
```

The important item to focus on is the use of `PkgConfigDeps`

2. The happy path (which is to use the packages from cache) works.
```bash
conan install . --output-folder=third-party --build=missing
```

Examine the contents of any *.pc file inside `third-party` folder and make note of the use of `prefix` and the values of
`libdir`, `includedir`, ...

They are correct.

3. The not so common or recommended path (i,e., [make a copy of the dependencies locally](^1))
[^1]: https://docs.conan.io/2/reference/extensions/deployers.html#direct-deploy

```bash
# doesn't matter if its direct_deploy or full_deploy, the issue is the same
conan install . --output-folder=third-party  --deployer=direct_deploy --deployer-folder=third-party --build=missing
```

Examine the contents of any *.pc file inside `third-party` folder and make note of the use of `prefix` and the values of
`libdir`, `includedir`, ...

Contents of libuv-static.pc is provided below to illustrate the issue:
```ini
prefix=third-party/direct_deploy/libuv
libdir=${prefix}/third-party/direct_deploy/libuv/lib
includedir=${prefix}/third-party/direct_deploy/libuv/include
bindir=${prefix}/third-party/direct_deploy/libuv/bin

Name: libuv-static
Description: Conan package: libuv-static
Version: 1.48.0
Libs: -L"${libdir}" -luv
Cflags: -I"${includedir}"
```

Notice that the value of the `prefix` is repeated for `libdir`, `includedir`, `bindir`...

The causes issues for the build system I am using (gn + ninja).  I am not sure how it could work for other build systems either.

Anyway, I chased the bug down and isolated it to  the function `_get_formatted_dirs(...)` in `conan/tools/gnu/pkgconfigdeps.py``. For the version I am on, the code looks as below:

```python
    @staticmethod
    def _get_formatted_dirs(folder_name, folders, prefix_path_):
        ret = {}
        for i, directory in enumerate(folders):
            directory = os.path.normpath(directory).replace("\\", "/")
            prefix = ""
            if not os.path.isabs(directory):
                prefix = "${prefix}/"
            elif directory.startswith(prefix_path_):
                prefix = "${prefix}/"
                directory = os.path.relpath(directory, prefix_path_).replace("\\", "/")
            suffix = str(i) if i else ""
            var_name = f"{folder_name}{suffix}"
            ret[var_name] = f"{prefix}{directory}"
        return ret
```
This code above does the right thing only for the shared dependency `*.pc` file generation. 

4. The fix 
I can't claim that I know the implications but I tested the code below and it works now for both use cases correctly. Please review and let me know if you want me to submit a PR. Happy if I don't have to and someone with more knowledge of conan than me can review and fix more quickly.

```python
    @staticmethod
    def _get_formatted_dirs(folder_name, folders, prefix_path_):
        ret = {}
        prefix = "${prefix}/"
        for i, directory in enumerate(folders):
            directory = os.path.normpath(directory).replace("\\", "/")
            directory = os.path.relpath(directory, prefix_path_).replace("\\", "/")
            suffix = str(i) if i else ""
            var_name = f"{folder_name}{suffix}"
            ret[var_name] = f"{prefix}{directory}"
        return ret
```
With this fix in place, the `*.pc` files are generated correctly. Here is `libuv-static.pc` after the fix

```ini
prefix=third-party/direct_deploy/libuv
libdir=${prefix}/lib
includedir=${prefix}/include
bindir=${prefix}/bin

Name: libuv-static
Description: Conan package: libuv-static
Version: 1.48.0
Libs: -L"${libdir}" -luv
Cflags: -I"${includedir}"
```


Discussion:
HI @vijay8i 

Thanks a lot for reporting it and the steps to replicate it. I could reproduce it on my own 👍 
I'll try to open a PR to fix this today. Indeed, the piece of code that fails is that. Thanks! 



Patch:
diff --git a/conan/api/subapi/install.py b/conan/api/subapi/install.py
index 0fb5e11089d..5a5b677f6cb 100644
--- a/conan/api/subapi/install.py
+++ b/conan/api/subapi/install.py
@@ -1,3 +1,5 @@
+import os
+
 from conan.internal.conan_app import ConanApp
 from conan.internal.deploy import do_deploys
 from conans.client.generators import write_generators
@@ -70,7 +72,9 @@ def install_consumer(self, deps_graph, generators=None, source_folder=None, outp
 
         # The previous .set_base_folders has already decided between the source_folder and output
         if deploy or deploy_package:
-            base_folder = deploy_folder or conanfile.folders.base_build
+            # Issue related: https://github.com/conan-io/conan/issues/16543
+            base_folder = os.path.abspath(deploy_folder) if deploy_folder \
+                else conanfile.folders.base_build
             do_deploys(self.conan_api, deps_graph, deploy, deploy_package, base_folder)
 
         final_generators = []
diff --git a/conan/tools/gnu/pkgconfigdeps.py b/conan/tools/gnu/pkgconfigdeps.py
index be968f3fff2..4e2160989cc 100644
--- a/conan/tools/gnu/pkgconfigdeps.py
+++ b/conan/tools/gnu/pkgconfigdeps.py
@@ -78,12 +78,11 @@ def _get_formatted_dirs(folder_name, folders, prefix_path_):
         ret = {}
         for i, directory in enumerate(folders):
             directory = os.path.normpath(directory).replace("\\", "/")
-            prefix = ""
-            if not os.path.isabs(directory):
-                prefix = "${prefix}/"
-            elif directory.startswith(prefix_path_):
+            if directory.startswith(prefix_path_):
                 prefix = "${prefix}/"
                 directory = os.path.relpath(directory, prefix_path_).replace("\\", "/")
+            else:
+                prefix = "" if os.path.isabs(directory) else "${prefix}/"
             suffix = str(i) if i else ""
             var_name = f"{folder_name}{suffix}"
             ret[var_name] = f"{prefix}{directory}"


Test patch:
diff --git a/test/functional/toolchains/gnu/test_pkgconfigdeps_autotools.py b/test/functional/toolchains/gnu/test_pkgconfigdeps_autotools.py
index 1d328cd8688..e6cd401db5d 100644
--- a/test/functional/toolchains/gnu/test_pkgconfigdeps_autotools.py
+++ b/test/functional/toolchains/gnu/test_pkgconfigdeps_autotools.py
@@ -110,5 +110,3 @@ def test(self):
         # Issue: https://github.com/conan-io/conan/issues/11867
         assert '-F/my/framework/file1' in client.out
         assert '-F/my/framework/file2' in client.out
-        assert "warning: directory not found for option '-F/my/framework/file1'" in client.out
-        assert "warning: directory not found for option '-F/my/framework/file2'" in client.out
diff --git a/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py b/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
index 50c2ec587aa..bbbc124f41f 100644
--- a/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
+++ b/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
@@ -757,3 +757,33 @@ def test_different_versions():
     c.run("install --requires=dep/2.3 -g CMakeDeps")
     config = c.load("dep-config.cmake")
     assert 'set(dep_VERSION_STRING "2.3")' in config
+
+
+def test_using_deployer_folder():
+    """
+    Related to: https://github.com/conan-io/conan/issues/16543
+
+    CMakeDeps was failing if --deployer-folder was used. The error looked like:
+
+    conans.errors.ConanException: Error in generator 'CMakeDeps': error generating context for 'dep/1.0': mydeploy/direct_deploy/dep/include is not absolute
+    """
+    c = TestClient()
+    profile = textwrap.dedent("""
+    [settings]
+    arch=x86_64
+    build_type=Release
+    compiler=apple-clang
+    compiler.cppstd=gnu17
+    compiler.libcxx=libc++
+    compiler.version=15
+    os=Macos
+    """)
+    c.save({
+        "profile": profile,
+        "dep/conanfile.py": GenConanfile("dep")})
+    c.run("create dep --version 1.0")
+    c.run("install --requires=dep/1.0 -pr profile --deployer=direct_deploy "
+          "--deployer-folder=mydeploy -g CMakeDeps")
+    content = c.load("dep-release-x86_64-data.cmake")
+    assert ('set(dep_PACKAGE_FOLDER_RELEASE "${CMAKE_CURRENT_LIST_DIR}/mydeploy/direct_deploy/dep")'
+            in content)
diff --git a/test/integration/toolchains/gnu/test_pkgconfigdeps.py b/test/integration/toolchains/gnu/test_pkgconfigdeps.py
index 29530e43129..467d4f1f48c 100644
--- a/test/integration/toolchains/gnu/test_pkgconfigdeps.py
+++ b/test/integration/toolchains/gnu/test_pkgconfigdeps.py
@@ -1098,3 +1098,23 @@ def requirements(self):
     # Now, it passes and creates the pc files correctly (the skipped one is not created)
     client.run("install .")
     assert "Requires:" not in client.load("pkg.pc")
+
+
+def test_using_deployer_folder():
+    """
+    Testing that the absolute path is kept as the prefix instead of the
+    relative path.
+
+    Issue related: https://github.com/conan-io/conan/issues/16543
+    """
+    client = TestClient()
+    client.save({"dep/conanfile.py": GenConanfile("dep", "0.1")})
+    client.run("create dep/conanfile.py")
+    client.run("install --requires=dep/0.1 --deployer=direct_deploy "
+               "--deployer-folder=mydeploy -g PkgConfigDeps")
+    content = client.load("dep.pc")
+    prefix_base = client.current_folder.replace('\\', '/')
+    assert f"prefix={prefix_base}/mydeploy/direct_deploy/dep" in content
+    assert "libdir=${prefix}/lib" in content
+    assert "includedir=${prefix}/include" in content
+    assert "bindir=${prefix}/bin" in content