Repository: SCons/scons

Issue:
Support unique option in CheckLib
This issue was originally created at: 2011-05-27 09:55:34.
This issue was reported by: `jcoffland`.
jcoffland said at 2011-05-27 09:55:34
>`CheckLib` currently supports an `append` option which when false causes the code to prepend instead.  It would be nice to also have a unique option which would make the function use either `PrependUnique` or `AppendUnique`.
> 
>e.g.:
```python
    if append:
        oldLIBS = context.AppendLIBS(l, unique)
    else:
        oldLIBS = context.PrependLIBS(l, unique)
```
> 
>This would also require modifying functions `AppendLIBS` and `PrependLIBS` in `SConf.py`:
```python
    def AppendLIBS(self, lib_name_list, unique=False):
        oldLIBS = self.env.get("LIBS", [])
        if unique:
            self.env.AppendUnique(LIBS=lib_name_list)
        else:
            self.env.Append(LIBS=lib_name_list)
        return oldLIBS

    def PrependLIBS(self, lib_name_list, unique=False):
        oldLIBS = self.env.get("LIBS", [])
        if unique:
            self.env.PrependUnique(LIBS=lib_name_list)
        else:
            self.env.Prepend(LIBS=lib_name_list)
        return oldLIBS
```



Discussion:

Resolving patch:
diff --git a/SCons/Conftest.py b/SCons/Conftest.py
--- a/SCons/Conftest.py
+++ b/SCons/Conftest.py
@@ -267,7 +267,7 @@ def CheckFunc(context, function_name, header = None, language = None):
 #ifdef __cplusplus
 extern "C"
 #endif
-char %s();""" % function_name
+char %s(void);""" % function_name
 
     lang, suffix, msg = _lang2suffix(language)
     if msg:
@@ -285,7 +285,7 @@ def CheckFunc(context, function_name, header = None, language = None):
 
 int main(void) {
 #if defined (__stub_%(name)s) || defined (__stub___%(name)s)
-  fail fail fail
+  #error "%(name)s has a GNU stub, cannot check"
 #else
   %(name)s();
 #endif
@@ -627,7 +627,7 @@ def CheckMember(context, aggregate_member, header = None, language = None):
 
 def CheckLib(context, libs, func_name = None, header = None,
              extra_libs = None, call = None, language = None, autoadd = 1,
-             append = True):
+             append=True, unique=False):
     """
     Configure check for a C or C++ libraries "libs".  Searches through
     the list of libraries, until one is found where the test succeeds.
@@ -713,9 +713,9 @@ def CheckLib(context, libs, func_name = None, header = None,
             if extra_libs:
                 l.extend(extra_libs)
             if append:
-                oldLIBS = context.AppendLIBS(l)
+                oldLIBS = context.AppendLIBS(l, unique)
             else:
-                oldLIBS = context.PrependLIBS(l)
+                oldLIBS = context.PrependLIBS(l, unique)
             sym = "HAVE_LIB" + lib_name
         else:
             oldLIBS = -1
diff --git a/SCons/SConf.py b/SCons/SConf.py
--- a/SCons/SConf.py
+++ b/SCons/SConf.py
@@ -923,14 +923,20 @@ def RunProg(self, text, ext):
         st, out = self.TryRun(text, ext)
         return not st, out
 
-    def AppendLIBS(self, lib_name_list):
+    def AppendLIBS(self, lib_name_list, unique=False):
         oldLIBS = self.env.get( 'LIBS', [] )
-        self.env.Append(LIBS = lib_name_list)
+        if unique:
+            self.env.AppendUnique(LIBS = lib_name_list)
+        else:
+            self.env.Append(LIBS = lib_name_list)
         return oldLIBS
 
-    def PrependLIBS(self, lib_name_list):
+    def PrependLIBS(self, lib_name_list, unique=False):
         oldLIBS = self.env.get( 'LIBS', [] )
-        self.env.Prepend(LIBS = lib_name_list)
+        if unique:
+            self.env.PrependUnique(LIBS = lib_name_list)
+        else:
+            self.env.Prepend(LIBS = lib_name_list)
         return oldLIBS
 
     def SetLIBS(self, val):
@@ -1067,7 +1073,8 @@ def CheckCXXHeader(context, header, include_quotes = '""'):
 
 
 def CheckLib(context, library = None, symbol = "main",
-             header = None, language = None, autoadd=True, append=True,) -> bool:
+             header = None, language = None, autoadd=True,
+             append=True, unique=False) -> bool:
     """
     A test for a library. See also CheckLibWithHeader.
     Note that library may also be None to test whether the given symbol
@@ -1083,7 +1090,7 @@ def CheckLib(context, library = None, symbol = "main",
     # ToDo: accept path for the library
     res = SCons.Conftest.CheckLib(context, library, symbol, header = header,
                                         language = language, autoadd = autoadd,
-                                        append=append)
+                                        append=append, unique=unique)
     context.did_show_result = True
     return not res
 
@@ -1091,7 +1098,7 @@ def CheckLib(context, library = None, symbol = "main",
 # Bram: Can only include one header and can't use #ifdef HAVE_HEADER_H.
 
 def CheckLibWithHeader(context, libs, header, language,
-                       call = None, autoadd=True, append=True) -> bool:
+                       call = None, autoadd=True, append=True, unique=False) -> bool:
     # ToDo: accept path for library. Support system header files.
     """
     Another (more sophisticated) test for a library.
@@ -1108,7 +1115,8 @@ def CheckLibWithHeader(context, libs, header, language,
         libs = [libs]
 
     res = SCons.Conftest.CheckLib(context, libs, None, prog_prefix,
-            call = call, language = language, autoadd=autoadd, append=append)
+            call = call, language = language, autoadd=autoadd,
+            append=append, unique=unique)
     context.did_show_result = 1
     return not res
 
diff --git a/SCons/SConfTests.py b/SCons/SConfTests.py
--- a/SCons/SConfTests.py
+++ b/SCons/SConfTests.py
@@ -32,6 +32,7 @@
 
 sys.stdout = io.StringIO()
 
+# a library that is sure to exist on the platform
 if sys.platform == 'win32':
     existing_lib = "msvcrt"
 else:
@@ -78,9 +79,13 @@ def _resetSConfState(self):
         #    - cygwin on Windows (using cmd.exe, not bash)
         #    - posix
         #    - msvc on Windows (hopefully)
-        if (not self.scons_env.Detect( self.scons_env.subst('$CXX') ) or
-            not self.scons_env.Detect( self.scons_env.subst('$CC') ) or
-            not self.scons_env.Detect( self.scons_env.subst('$LINK') )):
+        if not all(
+            (
+                self.scons_env.Detect(self.scons_env.subst('$CXX')),
+                self.scons_env.Detect(self.scons_env.subst('$CC')),
+                self.scons_env.Detect(self.scons_env.subst('$LINK')),
+            )
+        ):
             raise Exception("This test needs an installed compiler!")
         if self.scons_env['CXX'] == 'g++':
             global existing_lib
@@ -502,27 +507,59 @@ def test_CheckLib(self):
             r = sconf.CheckLib( ["hopefullynolib",existing_lib], "main", autoadd=0 )
             assert r, "did not find %s " % existing_lib
 
-            # CheckLib() with autoadd
             def libs(env):
                 return env.get('LIBS', [])
 
-            env = sconf.env.Clone()
-
+            # CheckLib() with combinations of autoadd, append
             try:
-                r = sconf.CheckLib( existing_lib, "main", autoadd=1 )
+                env = sconf.env.Clone()
+                r = sconf.CheckLib(existing_lib, "main", autoadd=True, append=True)
                 assert r, "did not find main in %s" % existing_lib
                 expect = libs(env) + [existing_lib]
                 got = libs(sconf.env)
                 assert got == expect, "LIBS: expected %s, got %s" % (expect, got)
 
+                env = sconf.env.Clone()
+                r = sconf.CheckLib(existing_lib, "main", autoadd=True, append=False)
+                assert r, "did not find main in %s" % existing_lib
+                expect = [existing_lib] + libs(env)
+                got = libs(sconf.env)
+                assert got == expect, "LIBS: expected %s, got %s" % (expect, got)
+
                 sconf.env = env.Clone()
-                r = sconf.CheckLib( existing_lib, "main", autoadd=0 )
+                r = sconf.CheckLib(existing_lib, "main", autoadd=False)
                 assert r, "did not find main in %s" % existing_lib
                 expect = libs(env)
                 got = libs(sconf.env)
                 assert got == expect, "before and after LIBS were not the same"
             finally:
                 sconf.env = env
+
+            # CheckLib() with unique
+            sconf.env.Append(LIBS=existing_lib)
+            try:
+                env = sconf.env.Clone()
+                r = sconf.CheckLib(
+                    existing_lib, "main", autoadd=True, append=True, unique=False
+                )
+                assert r, f"did not find main in {existing_lib}"
+
+                expect = libs(env) + [existing_lib]
+                got = libs(sconf.env)
+                assert got == expect, f"LIBS: expected {expect}, got {got}"
+
+                env = sconf.env.Clone()
+                r = sconf.CheckLib(
+                    existing_lib, "main", autoadd=True, append=True, unique=True
+                )
+                assert r, f"did not find main in {existing_lib}"
+
+                expect = libs(env)
+                got = libs(sconf.env)
+                assert got == expect, f"LIBS: expected {expect}, got {got}"
+            finally:
+                sconf.env = env
+
         finally:
             sconf.Finish()
 
@@ -565,13 +602,12 @@ def test_CheckLibWithHeader(self):
             r = sconf.CheckLibWithHeader( [existing_lib,"hopefullynolib"], ["stdio.h", "math.h"], "C", autoadd=0 )
             assert r, "did not find %s, #include stdio.h first" % existing_lib
 
-            # CheckLibWithHeader with autoadd
             def libs(env):
                 return env.get('LIBS', [])
 
-            env = sconf.env.Clone()
-
+            # CheckLibWithHeader with combinations of autoadd, append
             try:
+                env = sconf.env.Clone()
                 r = sconf.CheckLibWithHeader(
                     existing_lib, "math.h", "C", autoadd=True, append=True
                 )
@@ -600,6 +636,29 @@ def libs(env):
             finally:
                 sconf.env = env
 
+            # CheckLibWithHeader() with unique
+            sconf.env.Append(LIBS=existing_lib)
+            try:
+                env = sconf.env.Clone()
+                r = sconf.CheckLibWithHeader(
+                    existing_lib, "math.h", "C", autoadd=True, append=True, unique=False
+                )
+                assert r, f"did not find main in {existing_lib}"
+                expect = libs(env) + [existing_lib]
+                got = libs(sconf.env)
+                assert got == expect, f"LIBS: expected {expect}, got {got}"
+
+                env = sconf.env.Clone()
+                r = sconf.CheckLibWithHeader(
+                    existing_lib, "math.h", "C", autoadd=True, append=True, unique=True
+                )
+                assert r, f"did not find main in {existing_lib}"
+                expect = libs(env)
+                got = libs(sconf.env)
+                assert got == expect, f"LIBS: expected {expect}, got {got}"
+            finally:
+                sconf.env = env
+
         finally:
             sconf.Finish()
 


Test patch: