Repository: conan-io/conan-center-index

Issue:
[package] swig/4.0.2: Unable to build using shared=True
It appears, `conans.CMake` runs outside of run environment. This causes issues when an upstream provides a build tool that requires `LD_LIBRARY_PATHS`. For example, see the instructions below for `swig` when building with `shared=True` flags.

The failure resolves by using `RunEnvironment` explicitly. Is there a good reason not to use `RunEnvironment` _implicitly_? 
~~~patch
diff --git i/recipes/swig/all/test_package/conanfile.py w/recipes/swig/all/test_package/conanfile.py
index 8b165ecd..8dc4b9b5 100644
--- i/recipes/swig/all/test_package/conanfile.py
+++ w/recipes/swig/all/test_package/conanfile.py
@@ -1,4 +1,4 @@
-from conans import CMake, ConanFile, tools
+from conans import CMake, ConanFile, tools, RunEnvironment


 class TestPackageConan(ConanFile):
@@ -21,11 +21,13 @@ class TestPackageConan(ConanFile):

     def build(self):
         if self._can_build:
-            self._cmake.configure()
-            self._cmake.build()
+            env_build = RunEnvironment(self)
+            with tools.environment_append(env_build.vars):
+                self._cmake.configure()
+                self._cmake.build()

     def test(self):
         if not tools.cross_building(self.settings):
             if self._can_build:
                 self._cmake.test(output_on_failure=True)
-            self.run("swig -version")
+            self.run("swig -version", run_environment=True)
~~~

### Package and Environment Details (include every applicable attribute)
  * Package Name/Version: **swig/4.0.2**
  * Operating System+version: **Debian GNU/Linux 10 (buster)**
  * Compiler+version: **GCC 9**
  * Conan version: **conan 1.34.1**
  * Python version: **Python 3.9.2**

### Steps to reproduce (Include if Applicable)
~~~
$ conan create . swig/4.0.2@ -o '*:shared=True' --build=missing --build=swig
...
-- Build files have been written to: /scratch/adklimki/conan-center-index/recipes/swig/all/test_package/build/750833d398e7a041deb748846200c7f6e390a6f4
[1/4] Swig compile test.i for python
...
.conan/data/swig/4.0.2/_/_/package/8d9623162576838bf5e4e0b3fae3a5a1a6010552/bin/swig: error while loading shared libraries: libpcre.so: cannot open shared object file: No such file or directory
ninja: build stopped: subcommand failed.
ERROR: swig/4.0.2 (test package): Error in build() method, line 25
~~~




Discussion:
See https://github.com/conan-io/conan/issues/4691
There is no good reason to not use `with tools.run_environment(self)` in `build()` (AND `package()` usually for `conan create -kb`)  if a recipe has a build requirement whose executable might have linked to shared libs (pkgconf for example). But we often forget this tricky fact, and it's not tested in CCI since dependencies are always static.

Usually, when the executable links to shared libs in its own package (like pkgconf), it works on Windows but not on Unix platforms, but if it links to shared libs from another package, it fails on all platforms without this environment injection.

So yes it might be a good idea that build helpers inject these env vars by default.

Note that it might not be sufficient on Macos due to SIP (for example when the executable is called through `add_custom_command()` in upstream CMakeLists).

Resolving patch:
diff --git a/recipes/swig/all/conanfile.py b/recipes/swig/all/conanfile.py
--- a/recipes/swig/all/conanfile.py
+++ b/recipes/swig/all/conanfile.py
@@ -40,17 +40,25 @@ def source(self):
         tools.get(**self.conan_data["sources"][self.version])
         os.rename("swig-rel-{}".format(self.version), self._source_subfolder)
 
+    @property
+    def _user_info_build(self):
+        # If using the experimental feature with different context for host and
+        # build, the 'user_info' attributes of the 'build_requires' packages
+        # will be located into the 'user_info_build' object. In other cases they
+        # will be located into the 'deps_user_info' object.
+        return getattr(self, "user_info_build", None) or self.deps_user_info
+
     @contextmanager
     def _build_context(self):
         env = {}
         if self.settings.compiler != "Visual Studio":
-            env["YACC"] = self.deps_user_info["bison"].YACC
+            env["YACC"] = self._user_info_build["bison"].YACC
         if self.settings.compiler == "Visual Studio":
             with tools.vcvars(self.settings):
                 env.update({
-                    "CC": "{} cl -nologo".format(tools.unix_path(self.deps_user_info["automake"].compile)),
-                    "CXX": "{} cl -nologo".format(tools.unix_path(self.deps_user_info["automake"].compile)),
-                    "AR": "{} link".format(self.deps_user_info["automake"].ar_lib),
+                    "CC": "{} cl -nologo".format(tools.unix_path(self._user_info_build["automake"].compile)),
+                    "CXX": "{} cl -nologo".format(tools.unix_path(self._user_info_build["automake"].compile)),
+                    "AR": "{} link".format(self._user_info_build["automake"].ar_lib),
                     "LD": "link",
                 })
                 with tools.environment_append(env):


Test patch:
diff --git a/recipes/swig/all/test_package/conanfile.py b/recipes/swig/all/test_package/conanfile.py
--- a/recipes/swig/all/test_package/conanfile.py
+++ b/recipes/swig/all/test_package/conanfile.py
@@ -21,11 +21,12 @@ def _can_build(self):
 
     def build(self):
         if self._can_build:
-            self._cmake.configure()
-            self._cmake.build()
+            with tools.run_environment(self):
+                self._cmake.configure()
+                self._cmake.build()
 
     def test(self):
         if not tools.cross_building(self.settings):
             if self._can_build:
                 self._cmake.test(output_on_failure=True)
-            self.run("swig -version")
+            self.run("swig -version", run_environment=True)