[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: Merging Ctypes Python Branch

From: Eric Gillespie <epg_at_pretzelnet.org>
Date: 2007-08-31 01:15:38 CEST

"Sage La Torra" <sagelt@gmail.com> writes:

> As of last week, David James and I think that the Ctypes Python
> Binding Branch is ready for merging, or at least a thorough review in
> preparation for merging. The branch is available at
> http://svn.collab.net/repos/svn/branches/ctypes-python-bindings/.

As a first step to reviewing, I tried to build it. Currently,
you assume everything is installed on the linker search path, but
this is frequently not the case. So, I changed autogen.py and
ctypesgen/wrap.py to take -L, -R, and --rpath options (as well as
the -Wl,-prefixed forms) to specify libdirs to search.

I also changed autogen.py to use apr-1-config --ldflags --link-ld
so that ensuring autogen.py has the right apr-1-config is all a
user needs to do if all svn stuff is in the same libdir.

[[[
* autogen.py
  (option_W): Add optparse callback to parse -Wl,-prefixed linker
    options (typically used as -Wl,-R/some/dir to specify RPATH).
  (parser): Handle -L, -R, --rpath, and -W (using option_W) options,
    storing values into options.libdirs list.
  (get_apr_config): Initialize ldflags to the output of 'apr-1-config
    --ldflags --libs' so we pick up any libdir options, to be passed on to
    ctypesgen/wrap.py .
  Pass options.libdirs on to ctypesgen/wrap.py with -R option. Handle
  errors from ctypesgen/wrap.py .

* wrap.py
  (load_library): Take new optional libdirs argument; if provided, if CDLL
    couldn't find the library, and if the path from find_library is
    relative, try loading the library from each of the libdirs.
  (CtypesWrapper.begin_output): Save new optional libdirs argument in
    self.libdirs for foo.
  (CtypesWrapper.print_preamble): Pass self.libdirs along to load_library.
  (option_W): Add optparse callback to parse -Wl,-prefixed linker
    options (typically used as -Wl,-R/some/dir to specify RPATH).
  (main): Handle -L, -R, --rpath, and -W (using option_W) options, storing
    values into options.libdirs list.
]]]

Index: autogen.py
===================================================================
--- autogen.py (revision 26401)
+++ autogen.py (working copy)
@@ -6,6 +6,17 @@
 from tempfile import mkdtemp
 from glob import glob
 
+def option_W(option, opt, value, parser):
+ if len(value) < 4 or value[0:3] != 'l,-':
+ raise optparse.BadOptionError("not in '-Wl,<opt>' form: %s%s"
+ % (opt, value))
+ opt = value[2:]
+ if opt not in ['-L', '-R', '--rpath']:
+ raise optparse.BadOptionError("-Wl option must be -L, -R"
+ " or --rpath, not " + value[2:])
+ # Push the linker option onto the list for further parsing.
+ parser.rargs.insert(0, value)
+
 parser = OptionParser()
 parser.add_option("-a", "--apr-config", dest="apr_config",
                   help="The full path to your apr-1-config or apr-config script")
@@ -15,6 +26,12 @@
 parser.add_option("", "--save-preprocessed-headers", dest="filename",
                   help="Save the preprocessed headers to the specified "
                        "FILENAME")
+parser.add_option("-W", action="callback", callback=option_W, type='str',
+ metavar="l,OPTION",
+ help="where OPTION is -L, -R, or --rpath")
+parser.add_option("-L", "-R", "--rpath", action="append", dest="libdirs",
+ metavar="LIBDIR", help="Add LIBDIR to the search path")
+parser.set_defaults(libdirs=[])
 
 (options, args) = parser.parse_args()
 
@@ -48,6 +65,10 @@
             apr_include_dir = run_cmd("%s --includedir" % apr_config).strip()
             apr_version = run_cmd("%s --version" % apr_config).strip()
             cpp = run_cmd("%s --cpp" % apr_config).strip()
+
+ fout = run_cmd("%s --ldflags --link-ld" % apr_config)
+ if fout:
+ ldflags = fout.split()
             break
     else:
         print ferr
@@ -72,10 +93,9 @@
                         "to your Subversion installation using the --prefix\n"
                         "option.")
 
- ldflags = [
- "-lapr-%s" % apr_version[0],
- "-laprutil-%s" % apr_version[0],
- ]
+ # TODO: Use apu-1-config, as above:
+ # ldflags.extend(run_cmd('apu-1-config --ldflags --link-ld').split())
+ ldflags.append("-laprutil-%s" % apr_version[0])
 
     # List the libraries in the order they should be loaded
     libraries = [
@@ -124,16 +144,31 @@
 
 os.environ["LIBRARY_PATH"] = library_path
 
-cmd = ("cd %s && %s %s/ctypesgen/wrap.py --cpp '%s %s' %s "
+cmd = ["cd %s && %s %s/ctypesgen/wrap.py --cpp '%s %s' %s "
        "%s -o svn_all.py" % (tempdir, sys.executable, os.getcwd(),
- cpp, flags, ldflags, includes))
+ cpp, flags, ldflags, includes)]
+cmd.extend('-R ' + x for x in options.libdirs)
+cmd = ' '.join(cmd)
 
 if options.filename:
     cmd += " --save-preprocessed-headers=%s" % \
         os.path.abspath(options.filename)
 
 print cmd
-os.system(cmd)
+status = os.system(cmd)
+if os.WIFEXITED(status):
+ status = os.WEXITSTATUS(status)
+ if status != 0:
+ sys.exit(status)
+elif os.WIFSIGNALED(status):
+ sys.stderr.write("wrap.py killed with signal %d" % (os.WTERMSIG(status),))
+ sys.exit(2)
+elif os.WIFSTOPPED(status):
+ sys.stderr.write("wrap.py stopped with signal %d" % (os.WSTOPSIG(status),))
+ sys.exit(2)
+else:
+ sys.stderr.write("wrap.py exited with invalid status %d" % (status,))
+ sys.exit(2)
 
 func_re = re.compile(r"CFUNCTYPE\(POINTER\((\w+)\)")
 out = file("%s/svn_all2.py" % tempdir, "w")
Index: ctypesgen/wrap.py
===================================================================
--- ctypesgen/wrap.py (revision 35)
+++ ctypesgen/wrap.py (working copy)
@@ -14,11 +14,12 @@
 
 from ctypesparser import *
 import textwrap
-import sys, re
+import optparse, os, sys, re
+from errno import ENOENT
 from ctypes import CDLL, RTLD_GLOBAL, c_byte
 from ctypes.util import find_library
 
-def load_library(name, mode=RTLD_GLOBAL):
+def load_library(name, mode=RTLD_GLOBAL, libdirs=None):
     if os.name == "nt":
         return CDLL(name, mode=mode)
     path = find_library(name)
@@ -26,14 +27,34 @@
         # Maybe 'name' is not a library name in the linker style,
         # give CDLL a last chance to find the library.
         path = name
- return CDLL(path, mode=mode)
+ try:
+ return CDLL(path, mode=mode)
+ except OSError, e:
+ # XXX Sadly, ctypes raises OSError without setting errno.
+ if e.errno not in [ENOENT, None]:
+ raise
+ if os.path.isabs(path) or libdirs is None:
+ raise
+ # path is relative and the linker couldn't find it; if the
+ # user provided any libdirs, try those.
+ # XXX This isn't quite right; if the user provided libdirs, we
+ # should *only* try those; he may be specifically trying to
+ # avoid one on the system search path. But we're relying on
+ # find_library to turn e.g. 'apr-1' into 'libapr-1.so.0'
+ for libdir in set(libdirs):
+ try:
+ return CDLL(os.path.join(libdir, path), mode=mode)
+ except OSError, e:
+ if e.errno not in [ENOENT, None]:
+ raise
 
 class CtypesWrapper(CtypesParser, CtypesTypeVisitor):
     file=None
     def begin_output(self, output_file, library, link_modules=(),
                      emit_filenames=(), all_headers=False,
                      include_symbols=None, exclude_symbols=None,
- save_preprocessed_headers=None):
+ save_preprocessed_headers=None,
+ libdirs=None):
         self.library = library
         self.file = output_file
         self.all_names = []
@@ -51,6 +72,7 @@
             self.exclude_symbols = re.compile(exclude_symbols)
         self.preprocessor_parser.save_preprocessed_headers = \
             save_preprocessed_headers
+ self.libdirs = libdirs
 
         self.linked_symbols = {}
         for name in link_modules:
@@ -180,7 +202,7 @@
         }).lstrip()
         self.loaded_libraries = []
         for library in self.library:
- lib = load_library(library)
+ lib = load_library(library, libdirs=self.libdirs)
             if lib:
                 self.loaded_libraries.append(lib)
                 print >>self.file, textwrap.dedent("""
@@ -314,11 +336,19 @@
                     self.all_names.append(name)
                     break
 
+def option_W(option, opt, value, parser):
+ if len(value) < 4 or value[0:3] != 'l,-':
+ raise optparse.BadOptionError("not in '-Wl,<opt>' form: %s%s"
+ % (opt, value))
+ opt = value[2:]
+ if opt not in ['-L', '-R', '--rpath']:
+ raise optparse.BadOptionError("-Wl option must be -L, -R"
+ " or --rpath, not " + value[2:])
+ # Push the linker option onto the list for further parsing.
+ parser.rargs.insert(0, value)
+
 def main(*argv):
     from tempfile import NamedTemporaryFile
- import optparse
- import sys
- import os.path
 
     usage = 'usage: %prog [options] <header.h>'
     op = optparse.OptionParser(usage=usage)
@@ -341,7 +371,12 @@
     op.add_option('', '--save-preprocessed-headers', dest='filename',
                   help='Save the preprocessed headers to the specified '
                        'FILENAME')
-
+ op.add_option("-W", action="callback", callback=option_W, type='str',
+ metavar="l,OPTION",
+ help="where OPTION is -L, -R, or --rpath")
+ op.add_option("-L", "-R", "--rpath", action="append", dest="libdirs",
+ metavar="LIBDIR", help="Add LIBDIR to the search path")
+
     (options, args) = op.parse_args(list(argv[1:]))
     if len(args) < 1:
         print >> sys.stderr, 'No header files specified.'
@@ -363,7 +398,8 @@
                          all_headers=options.all_headers,
                          include_symbols=options.include_symbols,
                          exclude_symbols=options.exclude_symbols,
- save_preprocessed_headers=options.filename
+ save_preprocessed_headers=options.filename,
+ libdirs=options.libdirs,
                          )
     wrapper.preprocessor_parser.cpp = options.cpp
 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Fri Aug 31 01:12:46 2007

This is an archived mail posted to the Subversion Dev mailing list.