~njansson/dolfin/hpc

« back to all changes in this revision

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

  • Committer: Johannes Ring
  • Date: 2008-03-05 22:43:06 UTC
  • Revision ID: johannr@simula.no-20080305224306-2npsdyhfdpl2esji
The BIG commit!

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" % prefix, "exec_prefix=${prefix}\n", "includedir=%s\n" % includeDir, \
 
44
              "libdir=%s\n" % libDir, "compiler=%s\n" % compiler]
 
45
      for i in range(len(lines)):
 
46
          if not lines[i].strip():
 
47
              break
 
48
      body = lines[i:]
 
49
 
 
50
      # Might need to susbstitute things in the body, e.g. dependencies.
 
51
 
 
52
      if replaceDict is not None:
 
53
        for item in replaceDict:
 
54
          # find line(s) in body that match the substitution key:
 
55
          replLines = [ l for l in body if "@"+item+"@" in l ]
 
56
          # replace the key with the replaceDict item, and feed into the body
 
57
          # We support multiple occurences of a string, although that should be 
 
58
          # rare:
 
59
          for l in replLines:
 
60
            body[body.index(l)] = l.replace("@"+item+"@", replaceDict[item])
 
61
 
 
62
      f.writelines(header + body)
 
63
    finally:
 
64
      f.close()
 
65
  return _pcFunc
 
66
 
 
67
def _strFunc(target, source, env):
 
68
    return "Building %s from %s" % (target[0], ", ".join([str(s) for s in source]))
 
69
  
 
70
 
 
71
def generate(env, replace=None):
 
72
    """Place a template-based generator for pkg-config files in the BUILDERS."""
 
73
    # we might need to pass in things to replace in the pkg-config, we
 
74
    # can use the replace as a dict for that. The keys will be things to
 
75
    # replace in the template and the values will be the replacements.
 
76
    # 
 
77
    # We need to access the replace-dict inside _pcFunc, hence we must turn the 
 
78
    # _pcFunc into a closure.
 
79
    _pcFunc = generate_pcFunc(replace)
 
80
    env["BUILDERS"]["PkgConfigGenerator"] = Builder.Builder(action={".in": Action.Action(_pcFunc, \
 
81
            strfunction=_strFunc)}, suffix="")
 
82
 
 
83
 
 
84
def get_packgen(package):
 
85
  # Try to import and run the right pkgconfig generator:
 
86
  try:
 
87
    packgen = __import__("simula_scons.pkgconfiggenerators",globals(),locals())
 
88
  except:
 
89
    raise PkgconfigGeneratorsMissing()
 
90
  # Generate the pkgconfig file:
 
91
  # There should probably be a second try/except around the import of the 
 
92
  # pkgconfig generator for the specific module.
 
93
  ns = {}
 
94
  try:
 
95
    exec "from simula_scons.pkgconfiggenerators import %s" % (package.split('-',1)[0]) in ns
 
96
  except:
 
97
    raise PkgconfigGeneratorMissing(package)
 
98
  packgen = ns.get("%s" % (package.split('-',1)[0]))
 
99
  return packgen
 
100
 
 
101
 
 
102
class PkgConfig(object):
 
103
    """Handling of pkg-config files.
 
104
 
 
105
       Whenever pkg-config file must be read to handle a dependency, an 
 
106
       instance of this class will be created.
 
107
    """
 
108
    def __init__(self, package, env):
 
109
      
 
110
      # If the PKG_CONFIG_PATH variable is empty, we are probably on 
 
111
      # deep water here.
 
112
      # I'll create a suiteable directory and set as PKG_CONFIG_PATH 
 
113
      # right away.
 
114
 
 
115
      pkgconfdir = os.path.join(env.Dir("#scons").abspath,"pkgconfig")
 
116
      if not os.environ.has_key("PKG_CONFIG_PATH") or os.environ["PKG_CONFIG_PATH"] == "":
 
117
 
 
118
        if not os.path.isdir(pkgconfdir):
 
119
          os.makedirs(pkgconfdir)
 
120
        os.environ["PKG_CONFIG_PATH"]=pkgconfdir
 
121
        print "\n** Warning: Added %s \n    as PKG_CONFIG_PATH **" % (pkgconfdir)
 
122
      else:
 
123
        os.environ["SCONS_PKG_CONFIG_DIR"] = pkgconfdir
 
124
 
 
125
      self.package = package
 
126
      self.env = env
 
127
      try: 
 
128
        scons.runCommand("pkg-config", ["--exists", self.package])
 
129
        print "yes"
 
130
      except CommandError:
 
131
        print "no (pkg-config file not found)"
 
132
        print " Trying to generate pkg-config file for %s..." % (self.package),
 
133
 
 
134
        # Construct pkgconfig-file
 
135
        packgen = get_packgen(package)
 
136
 
 
137
#        # Try to import and run the right pkgconfig generator:
 
138
#        try:
 
139
#          packgen = __import__("simula_scons.pkgconfiggenerators",globals(),locals())
 
140
#        except:
 
141
#          raise PkgconfigGeneratorsMissing()
 
142
#        # Generate the pkgconfig file:
 
143
#        # There should probably be a second try/except around the import of the 
 
144
#        # pkgconfig generator for the specific module.
 
145
#        ns = {}
 
146
#        exec "from simula_scons.pkgconfiggenerators import %s" % (package.split('-',1)[0]) in ns
 
147
#        packgen = ns.get("%s" % (package.split('-',1)[0]))
 
148
 
 
149
        packgen.generatePkgConf(sconsEnv=env)
 
150
 
 
151
 
 
152
    def _pkgconfig(self, param):
 
153
        os.environ["PKG_CONFIG_ALLOW_SYSTEM_CFLAGS"] = "1"
 
154
        os.environ["PKG_CONFIG_ALLOW_SYSTEM_LIBS"] = "1"
 
155
        try: out, err = scons.runCommand("pkg-config", [param, self.package])
 
156
        except CommandError, err:
 
157
            raise PkgconfigError(self.package, "Error reported by pkg-config: `%s'" % err.stderr)
 
158
        return out
 
159
 
 
160
    def version(self):
 
161
        """Find out what version the package think it is"""
 
162
        return self._pkgconfig("--modversion")
 
163
 
 
164
    def includeDirs(self):
 
165
        out = self._pkgconfig("--cflags-only-I")
 
166
        dirs = []
 
167
        opts = out.split()
 
168
        for o in opts:
 
169
            dirs.append(o[2:])
 
170
        return dirs
 
171
 
 
172
    def libDirs(self):
 
173
        out = self._pkgconfig("--libs-only-L")
 
174
        dirs = []
 
175
        opts = out.split()
 
176
        for o in opts:
 
177
            dirs.append(o[2:])
 
178
        return dirs
 
179
 
 
180
    def compiler(self):
 
181
      # If the compiler, and maybe the compilertype variable is set, read and 
 
182
      # return as a tuple. If I can't figure out the compilertype, I use None
 
183
      # to denote 'unknown'
 
184
      compiler = self._pkgconfig("--variable=compiler")
 
185
      if compiler == "":
 
186
        return None
 
187
      else:
 
188
        return compiler
 
189
 
 
190
    def frameworks(self):
 
191
        out = self._pkgconfig("--libs")
 
192
        fw = re.findall(r"-framework (\S+)",out)
 
193
        return fw
 
194
 
 
195
    def libs(self):
 
196
        """return a set of libraries for lib. 
 
197
           On Darwin (MacOSX) a tuple with libraries and frameworks is returned
 
198
        """
 
199
        out = self._pkgconfig("--libs-only-l")
 
200
        libs = []
 
201
        opts = out.split()
 
202
        for o in opts:
 
203
            libs.append(o[2:])
 
204
        if self.env["PLATFORM"] == "darwin":
 
205
            return (libs, self.frameworks())
 
206
        return libs, []
 
207
 
 
208
    def cflags(self):
 
209
      return self._pkgconfig("--cflags")
 
210
 
 
211
    def ldflags(self):
 
212
      return self._pkgconfig("--libs")