Repository: conan-io/conan

Issue:
ConfigureEnvironment overwrites flags instead of augmenting
C/CPPFLAGS mainly.

Consider also the possibility to add UI so the user could add easily their own flags to the ConfigureEnvironment. Initially reported by @tru



Discussion:

Resolving patch:
diff --git a/conans/client/configure_environment.py b/conans/client/configure_environment.py
--- a/conans/client/configure_environment.py
+++ b/conans/client/configure_environment.py
@@ -63,11 +63,11 @@ def command_line(self):
             exe_linker_flags = " ".join(self._deps_cpp_info.exelinkflags)
             shared_linker_flags = " ".join(self._deps_cpp_info.sharedlinkflags)
             lib_paths = " ".join(["-L%s" % lib for lib in self._deps_cpp_info.lib_paths])
-            ldflags = 'LDFLAGS="%s %s %s %s %s"' % (lib_paths, libflags, archflag,
+            ldflags = 'LDFLAGS="$LDFLAGS %s %s %s %s %s"' % (lib_paths, libflags, archflag,
                                                     exe_linker_flags, shared_linker_flags)
             debug = "-g" if self.build_type == "Debug" else "-s -DNDEBUG"
             include_flags = " ".join(['-I%s' % i for i in self._deps_cpp_info.include_paths])
-            cflags = 'CFLAGS="%s %s %s %s"' % (archflag, " ".join(self._deps_cpp_info.cflags),
+            cflags = 'CFLAGS="$CFLAGS %s %s %s %s"' % (archflag, " ".join(self._deps_cpp_info.cflags),
                                                debug, include_flags)
 
             # Append the definition for libcxx
@@ -84,15 +84,15 @@ def command_line(self):
                     else:
                         all_cpp_flags.append("-stdlib=libstdc++")
 
-            cpp_flags = 'CPPFLAGS="%s %s %s %s"' % (archflag, " ".join(all_cpp_flags),
+            cpp_flags = 'CPPFLAGS="$CPPFLAGS %s %s %s %s"' % (archflag, " ".join(all_cpp_flags),
                                                     debug, include_flags)
             include_paths = ":".join(['"%s"' % lib for lib in self._deps_cpp_info.include_paths])
-            headers_flags = 'C_INCLUDE_PATH={0} CPP_INCLUDE_PATH={0}'.format(include_paths)
+            headers_flags = 'C_INCLUDE_PATH=$C_INCLUDE_PATH:{0} CPP_INCLUDE_PATH=$CPP_INCLUDE_PATH:{0}'.format(include_paths)
             command = "env %s %s %s %s %s" % (libs, ldflags, cflags, cpp_flags, headers_flags)
         elif self.os == "Windows" and self.compiler == "Visual Studio":
             cl_args = " ".join(['/I"%s"' % lib for lib in self._deps_cpp_info.include_paths])
             lib_paths = ";".join(['"%s"' % lib for lib in self._deps_cpp_info.lib_paths])
-            command = "SET LIB=%s;%%LIB%% && SET CL=%s" % (lib_paths, cl_args)
+            command = "SET LIB=%%LIB%%;%s && SET CL=%%CL%% %s" % (lib_paths, cl_args)
 
         # Add the rest of env variables from deps_env_info
         command += " ".join(get_setenv_variables_commands(self._deps_env_info,


Test patch:
diff --git a/conans/test/compile_helpers_test.py b/conans/test/compile_helpers_test.py
--- a/conans/test/compile_helpers_test.py
+++ b/conans/test/compile_helpers_test.py
@@ -3,6 +3,10 @@
 from conans.client.configure_environment import ConfigureEnvironment
 from conans.model.settings import Settings
 from conans.client.gcc import GCC
+import platform
+import os
+from conans.client.runner import ConanRunner
+from conans.test.tools import TestBufferConanOutput
 
 
 class MockWinSettings(Settings):
@@ -88,32 +92,32 @@ class CompileHelpersTest(unittest.TestCase):
 
     def configure_environment_test(self):
         env = ConfigureEnvironment(BuildInfoMock(), MockWinSettings())
-        self.assertEquals(env.command_line, 'SET LIB="path/to/lib1";"path/to/lib2";%LIB% && '
-                                            'SET CL=/I"path/to/includes/lib1" '
+        self.assertEquals(env.command_line, 'SET LIB=%LIB%;"path/to/lib1";"path/to/lib2" && '
+                                            'SET CL=%CL% /I"path/to/includes/lib1" '
                                             '/I"path/to/includes/lib2"')
 
         env = ConfigureEnvironment(BuildInfoMock(), MockLinuxSettings())
-        self.assertEquals(env.command_line, 'env LIBS="-llib1 -llib2" LDFLAGS="-Lpath/to/lib1 '
+        self.assertEquals(env.command_line, 'env LIBS="-llib1 -llib2" LDFLAGS="$LDFLAGS -Lpath/to/lib1 '
                                             '-Lpath/to/lib2 -llib1 -llib2 -m32 -framework thing -framework thing2" '
-                                            'CFLAGS="-m32 cflag1 -s -DNDEBUG '
+                                            'CFLAGS="$CFLAGS -m32 cflag1 -s -DNDEBUG '
                                             '-Ipath/to/includes/lib1 -Ipath/to/includes/lib2" '
-                                            'CPPFLAGS="-m32 cppflag1 -s -DNDEBUG '
+                                            'CPPFLAGS="$CPPFLAGS -m32 cppflag1 -s -DNDEBUG '
                                             '-Ipath/to/includes/lib1 -Ipath/to/includes/lib2" '
-                                            'C_INCLUDE_PATH="path/to/includes/lib1":'
+                                            'C_INCLUDE_PATH=$C_INCLUDE_PATH:"path/to/includes/lib1":'
                                             '"path/to/includes/lib2" '
-                                            'CPP_INCLUDE_PATH="path/to/includes/lib1":'
+                                            'CPP_INCLUDE_PATH=$CPP_INCLUDE_PATH:"path/to/includes/lib1":'
                                             '"path/to/includes/lib2"')
         # Not supported yet
         env = ConfigureEnvironment(BuildInfoMock(), MockWinGccSettings())
-        self.assertEquals(env.command_line, 'env LIBS="-llib1 -llib2" LDFLAGS="-Lpath/to/lib1 '
+        self.assertEquals(env.command_line, 'env LIBS="-llib1 -llib2" LDFLAGS="$LDFLAGS -Lpath/to/lib1 '
                                             '-Lpath/to/lib2 -llib1 -llib2 -m32 -framework thing -framework thing2" '
-                                            'CFLAGS="-m32 cflag1 -s -DNDEBUG '
+                                            'CFLAGS="$CFLAGS -m32 cflag1 -s -DNDEBUG '
                                             '-Ipath/to/includes/lib1 -Ipath/to/includes/lib2" '
-                                            'CPPFLAGS="-m32 cppflag1 -s -DNDEBUG '
+                                            'CPPFLAGS="$CPPFLAGS -m32 cppflag1 -s -DNDEBUG '
                                             '-Ipath/to/includes/lib1 -Ipath/to/includes/lib2" '
-                                            'C_INCLUDE_PATH="path/to/includes/lib1":'
+                                            'C_INCLUDE_PATH=$C_INCLUDE_PATH:"path/to/includes/lib1":'
                                             '"path/to/includes/lib2" '
-                                            'CPP_INCLUDE_PATH="path/to/includes/lib1":'
+                                            'CPP_INCLUDE_PATH=$CPP_INCLUDE_PATH:"path/to/includes/lib1":'
                                             '"path/to/includes/lib2"')
 
     def gcc_test(self):
@@ -122,3 +126,40 @@ def gcc_test(self):
 
         gcc = GCC(MockLinuxSettings("Debug"))
         self.assertEquals(gcc.command_line, "-g -m32 ")
+
+    def append_variables_test(self):
+        output = TestBufferConanOutput()
+        runner = ConanRunner()
+        if platform.system() != "Windows":
+            os.environ["LDFLAGS"] = "ldflag=23 otherldflag=33"
+            os.environ["CPPFLAGS"] = "-cppflag -othercppflag"
+            os.environ["CFLAGS"] = "-cflag"
+            os.environ["C_INCLUDE_PATH"] = "/path/to/c_include_path:/anotherpath"
+            os.environ["CPP_INCLUDE_PATH"] = "/path/to/cpp_include_path:/anotherpathpp"
+
+            env = ConfigureEnvironment(BuildInfoMock(), MockLinuxSettings())
+            runner(env.command_line, output=output)
+            self.assertIn("LDFLAGS=ldflag=23 otherldflag=33 -Lpath/to/lib1 -Lpath/to/lib2 -llib1 -llib2 -m32 -framework thing -framework thing2\n", output)
+            self.assertIn("CPPFLAGS=-cppflag -othercppflag -m32 cppflag1 -s -DNDEBUG -Ipath/to/includes/lib1 -Ipath/to/includes/lib2\n", output)
+            self.assertIn("CFLAGS=-cflag -m32 cflag1 -s -DNDEBUG -Ipath/to/includes/lib1 -Ipath/to/includes/lib2\n", output)
+            self.assertIn("C_INCLUDE_PATH=/path/to/c_include_path:/anotherpath:path/to/includes/lib1:path/to/includes/lib2\n", output)
+            self.assertIn("CPP_INCLUDE_PATH=/path/to/cpp_include_path:/anotherpathpp:path/to/includes/lib1:path/to/includes/lib2\n", output)
+
+            # Reset env vars to not mess with other tests
+            os.environ["LDFLAGS"] = ""
+            os.environ["CPPFLAGS"] = ""
+            os.environ["CFLAGS"] = ""
+            os.environ["C_INCLUDE_PATH"] = ""
+            os.environ["CPP_INCLUDE_PATH"] = ""
+        else:
+            os.environ["LIB"] = '"/path/to/lib.a"'
+            os.environ["CL"] = '/I"path/to/cl1" /I"path/to/cl2"'
+
+            env = ConfigureEnvironment(BuildInfoMock(), MockWinSettings())
+            command = "%s && SET" % env.command_line
+            runner(command, output=output)
+            self.assertIn('LIB="/path/to/lib.a";"path/to/lib1";"path/to/lib2"', output)
+            self.assertIn('CL=/I"path/to/cl1" /I"path/to/cl2" /I"path/to/includes/lib1" /I"path/to/includes/lib2"' , output)
+
+            os.environ["LIB"] = ""
+            os.environ["CL"] = ""