Commits

Gary Oberbrunner committed 49d0d2c Merge

Merge pull request #84, cyglink tool from David Rothenberger.
Also updated src/CHANGES.txt.

  • Participants
  • Parent commits f227a8a, c655b7c

Comments (0)

Files changed (10)

QMTest/TestCommon.py

     shobj_prefix = ''
     lib_prefix   = 'lib'
     lib_suffix   = '.a'
-    dll_prefix   = ''
+    dll_prefix   = 'cyg'
     dll_suffix   = '.dll'
 elif sys.platform.find('irix') != -1:
     exe_suffix   = ''
 
 RELEASE 2.3.1.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
 
+  From David Rothenberger:
+    - Added cyglink linker that uses Cygwin naming conventions for
+      shared libraries and automatically generates import libraries.
+
+  From Dirk Baechle:
+    - Update bootstrap.py so it can be used from any dir, to run
+      SCons from a source (non-installed) dir.
+
   From Gary Oberbrunner:
     - Test harness: fail_test() can now print a message to help debugging.
 
+  From Anatoly Techtonik:
+    - require rpmbuild when building SCons package.
+    - print full stack on certain errors, for debugging.
+
   From William Deegan:
     - VS2012 & VS2010 Resolve initialization issues by adding path to reg.exe
       in shell used to run batch files.

src/engine/MANIFEST.in

 SCons/Tool/BitKeeper.py
 SCons/Tool/c++.py
 SCons/Tool/cc.py
+SCons/Tool/cyglink.py
 SCons/Tool/cvf.py
 SCons/Tool/CVS.py
 SCons/Tool/default.py

src/engine/SCons/Tool/__init__.py

         assemblers = ['as']
         fortran_compilers = ['gfortran', 'f95', 'f90', 'g77']
         ars = ['ar']
+    elif str(platform) == 'cygwin':
+        "prefer GNU tools on Cygwin, except for a platform-specific linker"
+        linkers = ['cyglink', 'mslink', 'ilink']
+        c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc']
+        cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'c++']
+        assemblers = ['gas', 'nasm', 'masm']
+        fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
+        ars = ['ar', 'mslib']
     else:
         "prefer GNU tools on all other platforms"
         linkers = ['gnulink', 'mslink', 'ilink']

src/engine/SCons/Tool/__init__.xml

 </para>
 
 <para>
+On Cygwin systems, the
+&b-SharedLibrary;
+builder method will always build an import
+(<filename>.dll.a</filename>) library
+in addition to the shared (<filename>.dll</filename>) library,
+adding a <filename>.dll.a</filename> library with the same basename
+if there is not already a <filename>.dll.a</filename> file explicitly
+listed in the targets.
+</para>
+
+<para>
 Any object files listed in the
 <literal>source</literal>
 must have been built for a shared library
 </summary>
 </cvar>
 
-</sconsdoc>
+</sconsdoc>

src/engine/SCons/Tool/cyglink.py

+"""SCons.Tool.cyglink
+
+Customization of gnulink for Cygwin (http://www.cygwin.com/)
+
+There normally shouldn't be any need to import this module directly.
+It will usually be imported through the generic SCons.Tool.Tool()
+selection method.
+
+"""
+
+import SCons.Action
+import SCons.Util
+
+import gnulink
+
+def shlib_generator(target, source, env, for_signature):
+    cmd = SCons.Util.CLVar(['$SHLINK']) 
+
+    dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
+    if dll: cmd.extend(['-o', dll])
+
+    cmd.extend(['$SHLINKFLAGS', '$__RPATH'])
+
+    implib = env.FindIxes(target, 'IMPLIBPREFIX', 'IMPLIBSUFFIX')
+    if implib:
+        cmd.extend([
+            '-Wl,--out-implib='+implib.get_string(for_signature),
+            '-Wl,--export-all-symbols',
+            '-Wl,--enable-auto-import',
+            '-Wl,--whole-archive', '$SOURCES',
+            '-Wl,--no-whole-archive', '$_LIBDIRFLAGS', '$_LIBFLAGS'
+            ])
+    else:
+        cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS'])
+    
+    return [cmd]
+
+def shlib_emitter(target, source, env):
+    dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
+    no_import_lib = env.get('no_import_lib', 0)
+
+    if not dll or len(target) > 1:
+        raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX"))
+    
+    # Remove any "lib" after the prefix
+    pre = env.subst('$SHLIBPREFIX')
+    if dll.name[len(pre):len(pre)+3] == 'lib':
+        dll.name = pre + dll.name[len(pre)+3:]
+
+    orig_target = target
+    target = [env.fs.File(dll)]
+    target[0].attributes.shared = 1
+
+    # Append an import lib target
+    if not no_import_lib:
+        # Create list of target libraries as strings
+        target_strings = env.ReplaceIxes(orig_target[0],
+                                         'SHLIBPREFIX', 'SHLIBSUFFIX',
+                                         'IMPLIBPREFIX', 'IMPLIBSUFFIX')
+        
+        implib_target = env.fs.File(target_strings)
+        implib_target.attributes.shared = 1
+        target.append(implib_target)
+
+    return (target, source)
+                         
+
+shlib_action = SCons.Action.Action(shlib_generator, generator=1)
+
+def generate(env):
+    """Add Builders and construction variables for cyglink to an Environment."""
+    gnulink.generate(env)
+
+    env['LINKFLAGS']   = SCons.Util.CLVar('-Wl,-no-undefined')
+
+    env['SHLINKCOM'] = shlib_action
+    env['LDMODULECOM'] = shlib_action
+    env.Append(SHLIBEMITTER = [shlib_emitter])
+
+    env['SHLIBPREFIX']         = 'cyg'
+    env['SHLIBSUFFIX']         = '.dll'
+
+    env['IMPLIBPREFIX']        = 'lib'
+    env['IMPLIBSUFFIX']        = '.dll.a'
+
+def exists(env):
+    return gnulink.exists(env)
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:

src/engine/SCons/Tool/link.py

                     print "shlib_emitter_names: side effect: ", name
                 # add version_name to list of names to be a Side effect
                 version_names.append(version_name)
+            elif platform == 'cygwin':
+                shlib_suffix = env.subst('$SHLIBSUFFIX')
+                name = target[0].name
+                # generate library name with the version number
+                suffix_re = re.escape(shlib_suffix)
+                version_name = re.sub(suffix_re, '-' + re.sub('\.', '-', version) + shlib_suffix, name)
+                if Verbose:
+                    print "shlib_emitter_names: target is ", version_name
+                    print "shlib_emitter_names: side effect: ", name
+                # add version_name to list of names to be a Side effect
+                version_names.append(version_name)
+                
     except KeyError:
         version = None
     return version_names

test/LINK/VersionedLib.py

     'libtest.dylib',
     'libtest.2.5.4.dylib',
     ]
+elif platform == 'cygwin':
+    # All (?) the files we expect will get created in the current directory
+    files = [
+    'cygtest-2-5-4.dll',
+    'libtest-2-5-4.dll.a',
+    'test.os',
+    ]
+    # All (?) the files we expect will get created in the 'installtest' directory
+    instfiles = [
+    'cygtest-2-5-4.dll',
+    'libtest-2-5-4.dll.a',
+    ]
 elif platform == 'win32':
     # All (?) the files we expect will get created in the current directory
     files = [

test/Libs/SharedLibrary.py

 SharedLibrary(target = 'foo2',
               source = Split('f2a.c f2b.c f2c.c'),
               WINDOWS_INSERT_DEF = 1)
-env.SharedLibrary(target = 'foo3', source = ['f3a.c', 'f3b.c', 'f3c.c'])
+env.SharedLibrary(target = 'foo3', source = ['f3a.c', 'f3b.c', 'f3c.c'], no_import_lib = 1)
 env2.Program(target = 'prog', source = 'prog.c')
 """)
 
 test.run(program = test.workpath('prog'),
          stdout = "f1.c\nf2a.c\nf2b.c\nf2c.c\nf3a.c\nf3b.c\nf3c.c\nprog.c\n")
 
+if sys.platform == 'cygwin':
+    # Cygwin: Make sure the DLLs are prefixed correctly.
+    test.must_exist('cygfoo1.dll', 'cygfoo2.dll', 'cygfoo3.dll')
+    test.must_exist('libfoo1.dll.a', 'libfoo2.dll.a')
+    test.must_not_exist('foo3.dll.a')
+
+
 if sys.platform == 'win32' or sys.platform.find('irix') != -1:
     test.run(arguments = '-f SConstructFoo')
 else:

test/Libs/SharedLibraryIxes.py

 """
 
 import re
+import sys
 import TestSCons
 
 test = TestSCons.TestSCons()
 
 test.write('SConstruct', """
 import sys
+isCygwin = sys.platform == 'cygwin'
 isWindows = sys.platform == 'win32'
 isMingw = False
 if isWindows:
     return (source, libname)
 
 libmethods = [nodeInSrc, pathInSrc, nodeInLib, pathInLib]
-# We skip the nameInLib test for MinGW...it would fail, due to
+# We skip the nameInLib test for MinGW and Cygwin...they would fail, due to
 # the Tool's internal naming conventions
-if not isMingw:
+if not isMingw and not isCygwin:
     libmethods.extend([nameInLib])
 
 def buildAndlinkAgainst(builder, target, source,  method, lib, libname, **kw):
             if str(l)[-4:] == '.lib':
                 lib = [l]
                 break
-    # If we use MinGW and create a SharedLibrary, we get two targets: a DLL,
+    # If we use MinGW or Cygwin and create a SharedLibrary, we get two targets: a DLL,
     # and the import lib created by the "--out-implib" parameter. We always
     # want to link against the second one, in order to prevent naming issues
     # for the linker command line...
-    if isMingw and len(lib) > 1:
+    if (isMingw or isCygwin) and len(lib) > 1:
         lib = lib[1:]
         
     # Apply the naming method to be tested and call the specified Builder.
 expected = "goo.c\nfoo.c\nprog.c\n"
 
 for t in tests:
-    test.must_exist(t[1])
-    test.must_exist(t[2])
+    if sys.platform != 'cygwin':
+        test.must_exist(t[1])
+        test.must_exist(t[2])
+    else:
+        # Cygwin turns libFoo.xxx into cygFoo.xxx
+        for f in t[1:2]:
+            test.must_exist(re.sub('^lib', 'cyg', f))
+
     test.must_exist(t[3])
     test.run(program = test.workpath(t[3]), stdout=expected)