Commits

David Rothenberger committed dd9ee3c

Add a cyglink tool

Add cyglink, a specialization of gnulink with the following
properties:

1. Set SHLIBPREFIX to "cyg" and SHLIBSUFFIX = ".dll".
2. Remove any "lib" after "cyg", to accommodate build scripts that
name libraries "libFoo".
3. Create DLL import libraries.

  • Participants
  • Parent commits c8dbbaa

Comments (0)

Files changed (5)

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')
+    dll_name = str(dll)
+    if dll_name[len(pre):len(pre)+3] == 'lib':
+        dll_name = pre + dll_name[len(pre)+3:]
+        dll = env.fs.File(dll_name)
+
+    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