From 8aae133794ddeea09be2579d084ff87cd77b86f2 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Fri, 27 Jan 2023 08:00:28 -0700 Subject: Add unique kwarg to CheckLibs Minor tweak to CheckFunc - the dummy prototype should have a dummy arg list too (comment from Python setuptools discussion). Might as well fail the official way: #error instead of C syntax error. Fixes #2768 Signed-off-by: Mats Wichmann --- CHANGES.txt | 3 ++ RELEASE.txt | 8 ++++-- SCons/Conftest.py | 10 +++---- SCons/SConf.py | 24 ++++++++++------ SCons/SConfTests.py | 81 +++++++++++++++++++++++++++++++++++++++++++++-------- doc/man/scons.xml | 43 +++++++++++++++++++--------- 6 files changed, 128 insertions(+), 41 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 93be68d..f51f8b2 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -124,6 +124,9 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER based on what is known now, 3.12 itself should work with this release. - Add "append" keyword argument to Configure context's CheckLib and CheckLibWithHeader to control whether to append or prepend (issue #2767) + Also added "unique" keyword, to control whether a library is added + or not if it is already in the $LIBS construction var in the + configure context. (issue #2768). RELEASE 4.4.0 - Sat, 30 Jul 2022 14:08:29 -0700 diff --git a/RELEASE.txt b/RELEASE.txt index 01bf63b..b68432d 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -46,9 +46,11 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY - Preliminary support for Python 3.12. - Run LaTeX after biber/bibtex only if necessary - Configure context methods CheckLib and CheckLibWithHeader now expose - an additional keyword argument 'append' which controls whether to append - (the default) or prepend discovered libraries to $LIBS. The functionality - was always present but prepending could not be requested via the offical API. + two additional keyword arguments: 'append', which controls whether to append + (the default) or prepend discovered libraries to $LIBS, and 'unique', + which controls whether to add the library if it is already in the $LIBS + list. This brings the library-adding functionality in Configure in line + with the regular Append, AppendUnique, Prepend and PrependUnique methods. FIXES diff --git a/SCons/Conftest.py b/SCons/Conftest.py index 83175cb..3c52ef4 100644 --- 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 @@ char %s();""" % function_name 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 @@ int main(void) { 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 @@ return 0; 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 index 051c14c..85edd3a 100644 --- a/SCons/SConf.py +++ b/SCons/SConf.py @@ -923,14 +923,20 @@ class CheckContext: 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 index 172fba7..f0290e5 100644 --- a/SCons/SConfTests.py +++ b/SCons/SConfTests.py @@ -32,6 +32,7 @@ import TestCmd 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 @@ class SConfTestCase(unittest.TestCase): # - 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 @@ int main(void) { 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 @@ int main(void) { 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 @@ int main(void) { 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() diff --git a/doc/man/scons.xml b/doc/man/scons.xml index 15270e2..e79a267 100644 --- a/doc/man/scons.xml +++ b/doc/man/scons.xml @@ -3892,7 +3892,7 @@ Returns a boolean indicating success or failure. context.CheckFunc(function_name, [header, language]) Checks if function_name is usable -in the context's local environment using the compiler +in the context's local environment, using the compiler specified by language - that is, can a check referencing it be compiled using the current values of &cv-link-CFLAGS;, &cv-link-CPPFLAGS;, @@ -3913,17 +3913,21 @@ If omitted, the default stanza will be #ifdef __cplusplus extern "C" #endif -char function_name(); +char function_name(void); -Note: do not use header -to include the standard header file that declares -function_name - successful -compilation of the test program depends on using -a dummy prototype for it, -to avoid probems with compilers which object to -function signature mismatches. +Note: if header is supplied, +it should not +include the standard header file that declares +function_name, +and it should include a +dummy prototype similar to the default case. +Compilers reject builds where a function call does +not match the declared prototype as happens +if the "real" header is included, +and modern compilers are now rejecting +implicit function declarations. Returns a boolean indicating success or failure. @@ -3931,7 +3935,7 @@ function signature mismatches. - context.CheckLib([library, symbol, header, language, autoadd=True, append=True]) + context.CheckLib([library, symbol, header, language, autoadd=True, append=True, unique=False]) Checks if library @@ -3948,12 +3952,17 @@ linking the stub program), it is added to the &cv-link-LIBS; &consvar; in the context. if append is true (the default), the library is appended, otherwise it is prepended. +If unique is true, +and the library would otherwise be added but is +already present in &cv-link-LIBS; in the configure context, +it will not be added again. The default is False. library can be a list of library names, or None (the default if the argument is omitted). If the former, symbol is checked against -each library name in order, returning on the first +each library name in order, returning +(and reporting success) on the first successful test; if the latter, it is checked with the current value of &cv-LIBS; (in this case no library name would be added). @@ -3973,13 +3982,14 @@ at least one should be supplied. Returns a boolean indicating success or failure. Changed in version 4.5.0: added the -append parameter. +append and unique +parameters. - context.CheckLibWithHeader(library, header, [language, call, autoadd=True, append=True]) + context.CheckLibWithHeader(library, header, [language, call, autoadd=True, append=True, unique=False]) Provides an alternative to the @@ -4012,11 +4022,16 @@ is added to the &cv-link-LIBS; &consvar; in the context and the method returns. If append is true (the default), the library is appended, otherwise prepended. +If unique is true, +and the library would otherwise be added but is +already present in &cv-link-LIBS; in the configure context, +it will not be added again. The default is False. Returns a boolean indicating success or failure. Changed in version 4.5.0: added the -append parameter. +append and unique +parameters. -- cgit v0.12