~ubuntu-branches/ubuntu/maverick/dolfin/maverick

« back to all changes in this revision

Viewing changes to scons/simula-scons/simula_scons/pkgconfig.py

  • Committer: Bazaar Package Importer
  • Author(s): Johannes Ring
  • Date: 2008-09-16 08:41:20 UTC
  • Revision ID: james.westby@ubuntu.com-20080916084120-i8k3u6lhx3mw3py3
Tags: upstream-0.9.2
ImportĀ upstreamĀ versionĀ 0.9.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# Various functionality for handling pkg-config in a scons based build.
 
3
#
 
4
# The "public interface" here is the 'generate' method and the 'PkgConfig' 
 
5
# class. The 'generate' method can be used to generate a pkg-config file 
 
6
# based on a template. Within pycc this is used to generate a suiteable
 
7
# pkg-config file for the version of pycc currently build. 
 
8
# The 'PkgConfig' class is used to read pkg-config files using the pkg-config
 
9
# command, and output the result suitable for inclusion in scons build 
 
10
# environments.
 
11
 
 
12
import os, os.path, re, sys
 
13
 
 
14
# imports from the global 'SCons'
 
15
from SCons import Builder, Action
 
16
 
 
17
# import the local 'scons'
 
18
import simula_scons as scons
 
19
from simula_scons.Errors import CommandError, PkgconfigError, PkgconfigMissing, PkgconfigGeneratorsMissing, PkgconfigGeneratorMissing
 
20
 
 
21
def generate_pcFunc(replaceDict):
 
22
  def _pcFunc(target, source, env):
 
23
    """ Fill in .pc template. """
 
24
    f = file(str(source[0]))
 
25
    try: lines = f.readlines()
 
26
    finally: f.close()
 
27
 
 
28
    includeDir = env["includeDir"]
 
29
    libDir = env["libDir"]
 
30
    prefix = env["prefix"]
 
31
    f = file(str(target[0]), "w")
 
32
 
 
33
    # compiler:
 
34
    # if env["CXX"] is set (are we sure we always use C++ - probably not...)
 
35
    if env.has_key("CXX") and env["CXX"] != None:
 
36
      compiler=env["CXX"]
 
37
    else:
 
38
      compiler=""
 
39
 
 
40
    try:
 
41
      includeDir = includeDir.replace("$prefix", "${prefix}")
 
42
      libDir = libDir.replace("$prefix", "${exec_prefix}")
 
43
      header = ["prefix=%s\n" % repr(prefix)[1:-1],
 
44
                "exec_prefix=${prefix}\n",
 
45
                "includedir=%s\n" % repr(includeDir)[1:-1], \
 
46
                "libdir=%s\n" % repr(libDir)[1:-1],
 
47
                "compiler=%s\n" % compiler]
 
48
      for i in range(len(lines)):
 
49
          if not lines[i].strip():
 
50
              break
 
51
      body = lines[i:]
 
52
 
 
53
      # Might need to susbstitute things in the body, e.g. dependencies.
 
54
 
 
55
      if replaceDict is not None:
 
56
        for item in replaceDict:
 
57
          # find line(s) in body that match the substitution key:
 
58
          replLines = [ l for l in body if "@"+item+"@" in l ]
 
59
          # replace the key with the replaceDict item, and feed into the body
 
60
          # We support multiple occurences of a string, although that should be 
 
61
          # rare:
 
62
          for l in replLines:
 
63
            body[body.index(l)] = l.replace("@"+item+"@", replaceDict[item])
 
64
 
 
65
      f.writelines(header + body)
 
66
    finally:
 
67
      f.close()
 
68
  return _pcFunc
 
69
 
 
70
def _strFunc(target, source, env):
 
71
    return "Building %s from %s" % (target[0], ", ".join([str(s) for s in source]))
 
72
  
 
73
 
 
74
def generate(env, replace=None):
 
75
    """Place a template-based generator for pkg-config files in the BUILDERS."""
 
76
    # we might need to pass in things to replace in the pkg-config, we
 
77
    # can use the replace as a dict for that. The keys will be things to
 
78
    # replace in the template and the values will be the replacements.
 
79
    # 
 
80
    # We need to access the replace-dict inside _pcFunc, hence we must turn the 
 
81
    # _pcFunc into a closure.
 
82
    _pcFunc = generate_pcFunc(replace)
 
83
    env["BUILDERS"]["PkgConfigGenerator"] = Builder.Builder(action={".in": Action.Action(_pcFunc, \
 
84
            strfunction=_strFunc)}, suffix="")
 
85
 
 
86
 
 
87
def get_packgen(package):
 
88
  # Try to import and run the right pkgconfig generator:
 
89
  try:
 
90
    packgen = __import__("simula_scons.pkgconfiggenerators",globals(),locals())
 
91
  except:
 
92
    raise PkgconfigGeneratorsMissing()
 
93
  # Generate the pkgconfig file:
 
94
  # There should probably be a second try/except around the import of the 
 
95
  # pkgconfig generator for the specific module.
 
96
  ns = {}
 
97
  try:
 
98
    exec "from simula_scons.pkgconfiggenerators import %s" % (package.split('-',1)[0]) in ns
 
99
  except:
 
100
    raise PkgconfigGeneratorMissing(package)
 
101
  packgen = ns.get("%s" % (package.split('-',1)[0]))
 
102
  return packgen
 
103
 
 
104
 
 
105
class PkgConfig(object):
 
106
    """Handling of pkg-config files.
 
107
 
 
108
       Whenever pkg-config file must be read to handle a dependency, an 
 
109
       instance of this class will be created.
 
110
    """
 
111
    def __init__(self, package, env):
 
112
      
 
113
      # If the PKG_CONFIG_PATH variable is empty, we are probably on 
 
114
      # deep water here.
 
115
      # I'll create a suiteable directory and set as PKG_CONFIG_PATH 
 
116
      # right away.
 
117
 
 
118
      # Set up a temporary place for pkgconfig files. 
 
119
      pkgconfdir = os.path.join(env.Dir("#scons").abspath,"pkgconfig")
 
120
      # set this is SCONS_PKG_CONFIG_DIR, which should be the place the 
 
121
      # pkgconfiggenerators put pc-files during build
 
122
      os.environ["SCONS_PKG_CONFIG_DIR"] = pkgconfdir
 
123
      # Make sure that the directory exist:
 
124
      if not os.path.isdir(pkgconfdir):
 
125
        os.makedirs(pkgconfdir)
 
126
      
 
127
      if not os.environ.has_key("PKG_CONFIG_PATH") or os.environ["PKG_CONFIG_PATH"] == "":
 
128
        os.environ["PKG_CONFIG_PATH"]=pkgconfdir
 
129
        #print "\n** Warning: Added %s \n    as PKG_CONFIG_PATH **" % (pkgconfdir)
 
130
      elif os.environ.has_key("PKG_CONFIG_PATH") and pkgconfdir not in os.environ["PKG_CONFIG_PATH"]:
 
131
        pkgConfPath = os.environ["PKG_CONFIG_PATH"].split(os.path.pathsep)
 
132
        pkgConfPath.append(pkgconfdir)
 
133
        os.environ["PKG_CONFIG_PATH"] = os.path.pathsep.join(pkgConfPath)
 
134
        #print "\n** Warning: Added %s \n    in PKG_CONFIG_PATH **" % (pkgconfdir)
 
135
      
 
136
      self.package = package
 
137
      self.env = env
 
138
      try: 
 
139
        scons.runCommand("pkg-config", ["--exists", self.package])
 
140
        print "yes"
 
141
      except CommandError:
 
142
        print "no (pkg-config file not found)"
 
143
        print " Trying to generate pkg-config file for %s..." % (self.package),
 
144
 
 
145
        # Construct pkgconfig-file
 
146
        packgen = get_packgen(package)
 
147
 
 
148
#        # Try to import and run the right pkgconfig generator:
 
149
#        try:
 
150
#          packgen = __import__("simula_scons.pkgconfiggenerators",globals(),locals())
 
151
#        except:
 
152
#          raise PkgconfigGeneratorsMissing()
 
153
#        # Generate the pkgconfig file:
 
154
#        # There should probably be a second try/except around the import of the 
 
155
#        # pkgconfig generator for the specific module.
 
156
#        ns = {}
 
157
#        exec "from simula_scons.pkgconfiggenerators import %s" % (package.split('-',1)[0]) in ns
 
158
#        packgen = ns.get("%s" % (package.split('-',1)[0]))
 
159
 
 
160
        packgen.generatePkgConf(sconsEnv=env)
 
161
 
 
162
 
 
163
    def _pkgconfig(self, param):
 
164
        os.environ["PKG_CONFIG_ALLOW_SYSTEM_CFLAGS"] = "1"
 
165
        #os.environ["PKG_CONFIG_ALLOW_SYSTEM_LIBS"] = "1"
 
166
        try: out, err = scons.runCommand("pkg-config", [param, self.package])
 
167
        except CommandError, err:
 
168
            raise PkgconfigError(self.package, "Error reported by pkg-config: `%s'" % err.stderr)
 
169
        return out
 
170
 
 
171
    def version(self):
 
172
        """Find out what version the package think it is"""
 
173
        return self._pkgconfig("--modversion")
 
174
 
 
175
    def includeDirs(self):
 
176
        out = self._pkgconfig("--cflags-only-I")
 
177
        # Note that pkgconfig will not have spaces between -I and its argument
 
178
        return [i[2:] for i in out.split()]
 
179
 
 
180
    def libDirs(self):
 
181
        out = self._pkgconfig("--libs-only-L")
 
182
        dirs = []
 
183
        opts = out.split()
 
184
        for o in opts:
 
185
            dirs.append(o[2:])
 
186
        return dirs
 
187
 
 
188
    def linkOpts(self):
 
189
      return self.__extract_opts("--libs-only-other")
 
190
 
 
191
    def compileOpts(self, filter=["-D"]):
 
192
      opts = self.__extract_opts("--cflags-only-other")
 
193
      if not filter:
 
194
        return opts
 
195
      filtered = []
 
196
      for f in filter:
 
197
        filtered += [o for o in opts if o.startswith(f)]
 
198
      return filtered
 
199
 
 
200
    def __extract_opts(self, name):
 
201
      return [o.strip() for o in self._pkgconfig(name).split()]
 
202
 
 
203
    def compiler(self):
 
204
      # If the compiler, and maybe the compilertype variable is set, read and 
 
205
      # return as a tuple. If I can't figure out the compilertype, I use None
 
206
      # to denote 'unknown'
 
207
      compiler = self._pkgconfig("--variable=compiler")
 
208
      if compiler == "":
 
209
        return None
 
210
      else:
 
211
        return compiler
 
212
 
 
213
    def frameworks(self):
 
214
        out = self._pkgconfig("--libs")
 
215
        fw = re.findall(r"-framework (\S+)",out)
 
216
        return fw
 
217
 
 
218
    def libs(self):
 
219
        """return a set of libraries for lib. 
 
220
           On Darwin (MacOSX) a tuple with libraries and frameworks is returned
 
221
        """
 
222
        out = self._pkgconfig("--libs-only-l")
 
223
        libs = []
 
224
        opts = out.split()
 
225
        for o in opts:
 
226
            libs.append(o[2:])
 
227
        if self.env["PLATFORM"] == "darwin":
 
228
            return (libs, self.frameworks())
 
229
        return libs, []
 
230
 
 
231
    def cflags(self):
 
232
      return self._pkgconfig("--cflags")
 
233
 
 
234
    def ldflags(self):
 
235
      return self._pkgconfig("--libs")