Add LoadableModule support. (Michael McCracken)
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 7 Jan 2005 14:24:10 +0000 (14:24 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 7 Jan 2005 14:24:10 +0000 (14:24 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@1209 fdb21ef1-2011-0410-befe-b5e4ea1792b1

doc/man/scons.1
src/CHANGES.txt
src/engine/MANIFEST.in
src/engine/SCons/Defaults.py
src/engine/SCons/Tool/__init__.py
src/engine/SCons/Tool/applelink.py [new file with mode: 0644]
src/engine/SCons/Tool/link.py
test/LoadableModule.py [new file with mode: 0644]
test/SWIG/SWIG.py
test/import.py

index 449eacecb062afce81bf456417b2965f7a01015e..7b34e8aef03f16ff30c8d0949e8800bd42cb377e 100644 (file)
@@ -1581,6 +1581,16 @@ A synonym for the
 .B StaticLibrary
 builder method.
 
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.IP LoadableModule()
+.IP env.LoadableModule()
+On most systems,
+this is the same as
+.BR SharedLibrary ().
+On Mac OS X (Darwin) platforms,
+this creates a loadable module bundle.
+
+
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .IP M4()
 .IP env.M4()
@@ -5472,6 +5482,12 @@ The default list is:
 A function that converts a file name into a File instance relative to the
 target being built. 
 
+.IP FRAMEWORKSFLAGS
+On Mac OS X,
+frameworks options to be addad at
+the end of a command
+line building a loadable module.
+
 .IP GS
 The Ghostscript program used to convert PostScript to PDF files.
 
@@ -5654,6 +5670,35 @@ env = Environment(LATEXCOMSTR = "Building $TARGET from LaTeX input $SOURCES")
 .IP LATEXFLAGS
 General options passed to the LaTeX structured formatter and typesetter.
 
+.IP LDMODULE
+The linker for building loadable modules.
+By default, this is the same as $SHLINK.
+
+.IP LDMODULECOM
+The command line for building loadable modules.
+On Mac OS X, this uses the $LDMODULE,
+$LDMODULEFLAGS and $FRAMEWORKSFLAGS variables.
+On other systems, this is the same as $SHLINK.
+
+.IP LDMODULECOMSTR
+The string displayed when building loadable modules.
+If this is not set, then $LDMODULECOM (the command line) is displayed.
+
+.IP LDMODULEFLAGS
+General user options passed to the linker for building loadable modules.
+
+.IP LDMODULEPREFIX
+The prefix used for loadable module file names.
+On Mac OS X, this is null;
+on other systems, this is
+the same $SHLIBPREFIX.
+
+.IP LDMODULESUFFIX
+The suffix used for loadable module file names.
+On Mac OS X, this is null;
+on other systems, this is
+the same $SHLIBSUFFIX.
+
 .IP LEX
 The lexical analyzer generator.
 
index 11c8e624e2a82063d0c50e6a7a2bc0638ae3f70a..e13fa39753845e520527a4199a3946876b5b618e 100644 (file)
@@ -180,6 +180,19 @@ RELEASE 0.97 - XXX
   - Make ParseConfig() recognize and add -mno-cygwin to $LINKFLAGS and
     $CCFLAGS, and -mwindows to $LINKFLAGS.
 
+  From Michael McCracken:
+
+  - Add a new "applelink" tool to handle the things like Frameworks and
+    bundles that Apple has added to gcc for linking.
+
+  - Use more appropriate default search lists of linkers, compilers and
+    and other tools for the 'darwin' platform.
+
+  - Add a LoadableModule Builder that builds a bundle on Mac OS X (Darwin)
+    and a shared library on other systems.
+
+  - Improve SWIG tests for use on Mac OS X (Darwin).
+
   From Elliot Murphy:
 
   - Enhance the tests to guarantee persistence of ListOption
index 5c329bd0367577bc04eaf577b07c9627b76b9322..133ccade148603e078efe92cec9248468da1239e 100644 (file)
@@ -55,6 +55,7 @@ SCons/Tool/aixc++.py
 SCons/Tool/aixcc.py
 SCons/Tool/aixf77.py
 SCons/Tool/aixlink.py
+SCons/Tool/applelink.py
 SCons/Tool/ar.py
 SCons/Tool/as.py
 SCons/Tool/bcc32.py
index b3312f76f185b2081f3d4b97c1619766bd6a8b07..644dadffc6cc3aca6a89b492e5456ea0db001870 100644 (file)
@@ -131,6 +131,7 @@ ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
 LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
 ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
 
+LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
 ArAction = SCons.Action.Action("$ARCOM", "$ARCOMSTR")
 
 LexAction = SCons.Action.Action("$LEXCOM", "$LEXCOMSTR")
index 2c793d97bed05c80f2b968e947909a458652773a..5513f5e44cb2aeeb11d2b4f9effdd1d25a2a3024 100644 (file)
@@ -171,6 +171,29 @@ def createSharedLibBuilder(env):
 
     return shared_lib
 
+def createLoadableModuleBuilder(env):
+    """This is a utility function that creates the LoadableModule
+    Builder in an Environment if it is not there already.
+
+    If it is already there, we return the existing one.
+    """
+
+    try:
+        loadable_module = env['BUILDERS']['LoadableModule']
+    except KeyError:
+        action_list = [ SCons.Defaults.SharedCheck,
+                        SCons.Defaults.LdModuleLinkAction ]
+        ld_module = SCons.Builder.Builder(action = action_list,
+                                          emitter = "$SHLIBEMITTER",
+                                          prefix = '$LDMODULEPREFIX',
+                                          suffix = '$LDMODULESUFFIX',
+                                          target_scanner = SCons.Defaults.ProgScan,
+                                          src_suffix = '$SHOBJSUFFIX',
+                                          src_builder = 'SharedObject')
+        env['BUILDERS']['LoadableModule'] = ld_module
+
+    return ld_module
+
 def createObjBuilders(env):
     """This is a utility function that creates the StaticObject
     and SharedObject Builders in an Environment if they
@@ -309,6 +332,14 @@ def tool_list(platform, env):
         assemblers = ['as', 'gas']
         fortran_compilers = ['aixf77', 'g77', 'fortran']
         ars = ['ar']
+    elif str(platform) == 'darwin':
+        "prefer GNU tools on Mac OS X, except for some linkers and IBM tools"
+        linkers = ['applelink', 'gnulink']
+        c_compilers = ['gcc', 'cc']
+        cxx_compilers = ['g++', 'c++']
+        assemblers = ['as']
+        fortran_compilers = ['g77']
+        ars = ['ar']
     else:
         "prefer GNU tools on all other platforms"
         linkers = ['gnulink', 'mslink', 'ilink']
diff --git a/src/engine/SCons/Tool/applelink.py b/src/engine/SCons/Tool/applelink.py
new file mode 100644 (file)
index 0000000..87c92d4
--- /dev/null
@@ -0,0 +1,60 @@
+"""SCons.Tool.applelink
+
+Tool-specific initialization for the Apple gnu-like linker.
+
+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.
+
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import SCons.Util
+
+import gnulink
+
+def generate(env):
+    """Add Builders and construction variables for applelink to an
+    Environment."""
+    gnulink.generate(env)
+
+    env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib')
+
+    # override the default for loadable modules, which are different
+    # on OS X than dynamic shared libs.  echoing what XCode does for
+    # pre/suffixes:
+    env['LDMODULEPREFIX'] = '' 
+    env['LDMODULESUFFIX'] = '' 
+    env['LDMODULE'] = '$SHLINK'
+    env['LDMODULEFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -bundle')
+    env['LDMODULECOM'] = '$LDMODULE $LDMODULEFLAGS -o  ${TARGET} $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $FRAMEWORKSFLAGS' 
+
+
+
+def exists(env):
+    import sys
+    return sys.platform == 'darwin'
index 8248be9e2dcd6838237387a07f15af9d2d67efe5..51886345404aa6fa6955277753634e940d3749f4 100644 (file)
@@ -70,6 +70,17 @@ def generate(env):
     elif env['PLATFORM'] == 'aix':
         env['SHLIBSUFFIX'] = '.a'
 
+    # For most platforms, a loadable module is the same as a shared
+    # library.  Platforms which are different can override these, but
+    # setting them the same means that LoadableModule works everywhere.
+    SCons.Tool.createLoadableModuleBuilder(env)
+    env['LDMODULE'] = '$SHLINK'
+    env['LDMODULEPREFIX'] = '$SHLIBPREFIX' 
+    env['LDMODULESUFFIX'] = '$SHLIBSUFFIX' 
+    env['LDMODULEFLAGS'] = '$SHLINKFLAGS'
+    env['LDMODULECOM'] = '$SHLINKCOM'
+
+
 
 def exists(env):
     # This module isn't really a Tool on its own, it's common logic for
diff --git a/test/LoadableModule.py b/test/LoadableModule.py
new file mode 100644 (file)
index 0000000..f3b1959
--- /dev/null
@@ -0,0 +1,117 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os
+import string
+import sys
+
+import TestCmd
+import TestSCons
+
+dll_ = TestSCons.dll_
+_dll = TestSCons._dll
+
+test = TestSCons.TestSCons()
+
+# Some systems apparently need -ldl on the link line, others don't.
+no_dl_lib = "env.Program(target = 'dlopenprog', source = 'dlopenprog.c')"
+use_dl_lib = "env.Program(target = 'dlopenprog', source = 'dlopenprog.c', LIBS=['dl'])"
+
+dlopen_line = {
+    'darwin' : no_dl_lib,
+    'freebsd4' : no_dl_lib,
+    'linux2' : use_dl_lib,
+}
+platforms_with_dlopen = dlopen_line.keys()
+
+test.write('SConstruct', """
+env = Environment()
+# dlopenprog tries to dynamically load foo1 at runtime using dlopen().
+env.LoadableModule(target = 'foo1', source = 'f1.c')
+""" + dlopen_line.get(sys.platform, ''))
+
+    
+test.write('f1.c', r"""
+#include <stdio.h>
+
+void
+f1(void)
+{
+       printf("f1.c\n");
+        fflush(stdout);
+}
+""")
+
+dlopenprog = r"""
+#include <errno.h>
+#include <stdio.h>
+#include <dlfcn.h>
+
+extern int errno;
+
+int
+main(int argc, char *argv[])
+{
+       argv[argc++] = "--";
+        void *foo1_shobj = dlopen("__foo1_name__", RTLD_NOW);
+       if(!foo1_shobj){
+         printf("Error loading foo1 '__foo1_name__' library at runtime, exiting.\n");
+         printf("%d\n", errno);
+         perror("");
+         return -1;
+       }
+       void (*f1)() = dlsym(foo1_shobj, "f1\0");
+       (*f1)();
+       printf("dlopenprog.c\n");
+        dlclose(foo1_shobj);
+       return 0;
+}
+"""
+
+# Darwin dlopen()s a bundle name "foo1",
+# other systems dlopen() a traditional libfoo1.so file.
+foo1_name = {'darwin' : 'foo1'}.get(sys.platform, dll_+'foo1'+_dll)
+
+test.write('dlopenprog.c',
+           string.replace(dlopenprog, '__foo1_name__', foo1_name))
+
+test.run(arguments = '.',
+         stderr=TestSCons.noisy_ar,
+         match=TestSCons.match_re_dotall)
+
+if string.find(sys.platform, 'darwin') != -1:
+    test.run(program='/usr/bin/file',
+             arguments = "foo1",
+             stdout="foo1: Mach-O bundle ppc\n")
+
+if sys.platform in platforms_with_dlopen:
+    os.environ['LD_LIBRARY_PATH'] = test.workpath()
+    test.run(program = test.workpath('dlopenprog'),
+             stdout = "f1.c\ndlopenprog.c\n")
+                                 
+
+
+test.pass_test()
index 2a0ee329db0a97f26a38683fceae5cab86d33d7a..af76d6c4e45ca682e551090b055ee4dab23e7658 100644 (file)
@@ -29,10 +29,24 @@ import string
 import sys
 import TestSCons
 
-python = TestSCons.python
+if sys.platform =='darwin':
+    # change to make it work with stock OS X python framework
+    # we can't link to static libpython because there isn't one on OS X
+    # so we link to a framework version. However, testing must also
+    # use the same version, or else you get interpreter errors.
+    python = "/System/Library/Frameworks/Python.framework/Versions/Current/bin/python"
+else:
+    python = TestSCons.python
+    
 _exe   = TestSCons._exe
 _obj   = TestSCons._obj
-_dll   = TestSCons._dll
+
+# swig-python expects specific filenames.
+# the platform specific suffix won't necessarily work.
+if sys.platform == 'win32':
+    _dll = '.dll'
+else:
+    _dll   = '.so' 
 
 test = TestSCons.TestSCons()
 
@@ -106,6 +120,18 @@ if swig:
 
     version = sys.version[:3] # see also sys.prefix documentation
 
+    # handle testing on other platforms:
+    frameworks = ''
+    ldmodule_prefix = ''
+    platform_sys_prefix = sys.prefix
+    if sys.platform == 'darwin':
+        # OS X has a built-in Python but no static libpython
+        # so you should link to it using apple's 'framework' scheme.
+        # (see top of file for further explanation)
+        frameworks = '-framework Python'
+        ldmodule_prefix = '_'
+        platform_sys_prefix = '/System/Library/Frameworks/Python.framework/Versions/%s/' % version
+    
     test.write("wrapper.py",
 """import os
 import string
@@ -116,15 +142,18 @@ os.system(string.join(sys.argv[1:], " "))
 
     test.write('SConstruct', """
 foo = Environment(SWIGFLAGS='-python',
-                  CPPPATH='%s/include/python%s/',
+                  CPPPATH='%(platform_sys_prefix)s/include/python%(version)s/',
                   SHCCFLAGS='',
-                  SHOBJSUFFIX='.o',
-                  SHLIBPREFIX='')
+                  LDMODULEPREFIX='%(ldmodule_prefix)s',
+                  LDMODULESUFFIX='%(_dll)s',
+                  FRAMEWORKSFLAGS='%(frameworks)s',
+                  )
+
 swig = foo.Dictionary('SWIG')
-bar = foo.Copy(SWIG = r'%s wrapper.py ' + swig)
-foo.SharedLibrary(target = 'foo', source = ['foo.c', 'foo.i'])
-bar.SharedLibrary(target = 'bar', source = ['bar.c', 'bar.i'])
-""" % (sys.prefix, version, python))
+bar = foo.Copy(SWIG = r'%(python)s wrapper.py ' + swig)
+foo.LoadableModule(target = 'foo', source = ['foo.c', 'foo.i'])
+bar.LoadableModule(target = 'bar', source = ['bar.c', 'bar.i'])
+""" % locals())
 
     test.write("foo.c", """\
 char *
@@ -160,7 +189,7 @@ bar_string()
 extern char *bar_string();
 """)
 
-    test.run(arguments = 'foo' + _dll)
+    test.run(arguments = ldmodule_prefix+'foo' + _dll)
 
     test.fail_test(os.path.exists(test.workpath('wrapper.out')))
 
@@ -171,9 +200,9 @@ print foo.foo_string()
 This is foo.c!
 """)
 
-    test.up_to_date(arguments = 'foo' + _dll)
+    test.up_to_date(arguments = ldmodule_prefix+'foo' + _dll)
 
-    test.run(arguments = 'bar' + _dll)
+    test.run(arguments = ldmodule_prefix+'bar' + _dll)
 
     test.fail_test(test.read('wrapper.out') != "wrapper.py\n")
 
index a8a86bf7f79e435c53de6a92ecc32c5b0e6b0391..1aae7ce1bd94fbcdfa8ccc5f27084c2af75cc011 100644 (file)
@@ -59,6 +59,7 @@ tools = [
     'aixcc',
     'aixf77',
     'aixlink',
+    'applelink',
     'ar',
     'as',
     'bcc32',