setup.py 14.1 KB
Newer Older
André Anjos's avatar
André Anjos committed
1 2 3 4 5
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Andre Anjos <andre.anjos@idiap.ch>
# Mon 16 Apr 08:18:08 2012 CEST

6 7
bob_packages = ['bob.core', 'bob.io.base']

André Anjos's avatar
André Anjos committed
8
import os
André Anjos's avatar
André Anjos committed
9
from setuptools import setup, find_packages, dist
10
dist.Distribution(dict(setup_requires=['bob.extension', 'bob.blitz'] + bob_packages))
André Anjos's avatar
André Anjos committed
11
from bob.extension.utils import egrep, find_header, find_library
12
from bob.blitz.extension import Extension, Library, build_ext
André Anjos's avatar
André Anjos committed
13

14 15 16
from bob.extension.utils import load_requirements
build_requires = load_requirements()

17 18 19
# Define package version
version = open("version.txt").read().rstrip()

20
packages = ['boost', 'libpng']
21
boost_modules = ['system', 'filesystem']
22

André Anjos's avatar
André Anjos committed
23

24 25
def libjpeg_version(header):

26 27
  vv = egrep(header, r"#\s*define\s+JPEG_LIB_VERSION_(MINOR|MAJOR)\s+(\d+)")
  if not len(vv): return None
28 29

  # we have a match, produce a string version of the version number
30 31
  major = int(vv[0].group(2))
  minor = int(vv[1].group(2))
32 33
  return '%d.%d' % (major, minor)

34 35
def libjpeg_turbo_version(header):

36 37
  vv = egrep(header, r"#\s*define\s+LIBJPEG_TURBO_VERSION\s+([\d\.]+)")
  if not len(vv): return None
38
  return vv[0].group(1) + '-turbo'
39

40 41 42 43 44 45
class jpeg:

  def __init__ (self, requirement='', only_static=False):
    """
    Searches for libjpeg in stock locations. Allows user to override.

André Anjos's avatar
André Anjos committed
46
    If the user sets the environment variable BOB_PREFIX_PATH, that prefixes
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
    the standard path locations.

    Parameters:

    requirement, str
      A string, indicating a version requirement for this library. For example,
      ``'>= 8.2'``.

    only_static, boolean
      A flag, that indicates if we intend to link against the static library
      only. This will trigger our library search to disconsider shared
      libraries when searching.
    """

    self.name = 'libjpeg'
    header = 'jpeglib.h'

    candidates = find_header(header)

    if not candidates:
André Anjos's avatar
André Anjos committed
67
      raise RuntimeError("could not find %s's `%s' - have you installed %s on this machine?" % (self.name, header, self.name))
68 69 70 71 72 73

    found = False

    if not requirement:
      self.include_directory = os.path.dirname(candidates[0])
      self.version = libjpeg_version(candidates[0])
74 75 76 77 78 79 80

      # special condition (using libjpeg-turbo instead)
      if self.version is None:
        turbo_candidates = find_header('jconfig.h')
        if turbo_candidates:
          self.version = libjpeg_turbo_version(turbo_candidates[0])

81 82 83 84 85 86 87 88 89
      found = True

    else:

      # requirement is 'operator' 'version'
      operator, required = [k.strip() for k in requirement.split(' ', 1)]

      # now check for user requirements
      for candidate in candidates:
90 91
        vv = libjpeg_version(candidate)
        available = LooseVersion(vv)
92 93 94 95 96 97
        if (operator == '<' and available < required) or \
           (operator == '<=' and available <= required) or \
           (operator == '>' and available > required) or \
           (operator == '>=' and available >= required) or \
           (operator == '==' and available == required):
          self.include_directory = os.path.dirname(candidate)
98
          self.version = vv
99 100 101 102
          found = True
          break

    if not found:
André Anjos's avatar
André Anjos committed
103
      raise RuntimeError("could not find the required (%s) version of %s on the file system (looked at: %s)" % (requirement, self.name, ', '.join(candidates)))
104 105 106 107 108 109 110 111 112 113

    # normalize
    self.include_directory = os.path.normpath(self.include_directory)

    # find library
    prefix = os.path.dirname(os.path.dirname(self.include_directory))
    module = 'jpeg'
    candidates = find_library(module, version=self.version, prefixes=[prefix], only_static=only_static)

    if not candidates:
114
      raise RuntimeError("cannot find required %s binary module `%s' - make sure `%s' is installed on `%s'" % (self.name, module, self.name, prefix))
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132

    # libraries
    self.libraries = []
    name, ext = os.path.splitext(os.path.basename(candidates[0]))
    if ext in ['.so', '.a', '.dylib', '.dll']:
      self.libraries.append(name[3:]) #strip 'lib' from the name
    else: #link against the whole thing
      self.libraries.append(':' + os.path.basename(candidates[0]))

    # library path
    self.library_directory = os.path.dirname(candidates[0])

  def macros(self):
    return [
        ('HAVE_%s' % self.name.upper(), '1'),
        ('%s_VERSION' % self.name.upper(), '"%s"' % self.version),
        ]

André Anjos's avatar
André Anjos committed
133 134
def libtiff_version(header):

135 136 137
  vv = egrep(header, r"#\s*define\s+TIFFLIB_VERSION_STR\s+\"LIBTIFF,\s+Version\s+([\d\.]+).*")
  if not len(vv): return None
  return vv[0].group(1)
André Anjos's avatar
André Anjos committed
138 139 140 141 142 143 144

class tiff:

  def __init__ (self, requirement='', only_static=False):
    """
    Searches for libtiff in stock locations. Allows user to override.

André Anjos's avatar
André Anjos committed
145
    If the user sets the environment variable BOB_PREFIX_PATH, that prefixes
André Anjos's avatar
André Anjos committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
    the standard path locations.

    Parameters:

    requirement, str
      A string, indicating a version requirement for this library. For example,
      ``'>= 8.2'``.

    only_static, boolean
      A flag, that indicates if we intend to link against the static library
      only. This will trigger our library search to disconsider shared
      libraries when searching.
    """

    self.name = 'libtiff'
    header = 'tiff.h'

    candidates = find_header(header)

    if not candidates:
      raise RuntimeError("could not find %s's `%s' - have you installed %s on this machine?" % (self.name, header, self.name))

    found = False

    if not requirement:
      self.include_directory = os.path.dirname(candidates[0])
      directory = os.path.dirname(candidates[0])
      version_header = os.path.join(directory, 'tiffvers.h')
      self.version = libtiff_version(version_header)
      found = True

    else:

      # requirement is 'operator' 'version'
      operator, required = [k.strip() for k in requirement.split(' ', 1)]

      # now check for user requirements
      for candidate in candidates:
        directory = os.path.dirname(candidate)
        version_header = os.path.join(directory, 'tiffvers.h')
186 187
        vv = libtiff_version(version_header)
        available = LooseVersion(vv)
André Anjos's avatar
André Anjos committed
188 189 190 191 192 193
        if (operator == '<' and available < required) or \
           (operator == '<=' and available <= required) or \
           (operator == '>' and available > required) or \
           (operator == '>=' and available >= required) or \
           (operator == '==' and available == required):
          self.include_directory = os.path.dirname(candidate)
194
          self.version = vv
André Anjos's avatar
André Anjos committed
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
          found = True
          break

    if not found:
      raise RuntimeError("could not find the required (%s) version of %s on the file system (looked at: %s)" % (requirement, self.name, ', '.join(candidates)))

    # normalize
    self.include_directory = os.path.normpath(self.include_directory)

    # find library
    prefix = os.path.dirname(os.path.dirname(self.include_directory))
    module = 'tiff'
    candidates = find_library(module, version=self.version, prefixes=[prefix], only_static=only_static)

    if not candidates:
210
      raise RuntimeError("cannot find required %s binary module `%s' - make sure `%s' is installed on `%s'" % (self.name, module, self.name, prefix))
André Anjos's avatar
André Anjos committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228

    # libraries
    self.libraries = []
    name, ext = os.path.splitext(os.path.basename(candidates[0]))
    if ext in ['.so', '.a', '.dylib', '.dll']:
      self.libraries.append(name[3:]) #strip 'lib' from the name
    else: #link against the whole thing
      self.libraries.append(':' + os.path.basename(candidates[0]))

    # library path
    self.library_directory = os.path.dirname(candidates[0])

  def macros(self):
    return [
        ('HAVE_%s' % self.name.upper(), '1'),
        ('%s_VERSION' % self.name.upper(), '"%s"' % self.version),
        ]

229 230
def libgif_version(header):

231 232 233 234
  vv = egrep(header, r"#\s*define\s+GIFLIB_(RELEASE|MINOR|MAJOR)\s+(\d+)")
  if not len(vv):
    vv = egrep(header, r"#\s*define\s+GIF_LIB_VERSION\s+\"\s*Version\s+([\d\.]+).*\"")
    if not len(vv): return None
235 236

    # old style
237
    return vv[0].group(1)
238 239

  # we have a match, produce a string version of the version number
240 241 242
  major = int(vv[0].group(2))
  minor = int(vv[1].group(2))
  release = int(vv[2].group(2))
243 244 245 246 247 248 249 250
  return '%d.%d.%d' % (major, minor, release)

class gif:

  def __init__ (self, requirement='', only_static=False):
    """
    Searches for libgif in stock locations. Allows user to override.

André Anjos's avatar
André Anjos committed
251
    If the user sets the environment variable BOB_PREFIX_PATH, that prefixes
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
    the standard path locations.

    Parameters:

    requirement, str
      A string, indicating a version requirement for this library. For example,
      ``'>= 8.2'``.

    only_static, boolean
      A flag, that indicates if we intend to link against the static library
      only. This will trigger our library search to disconsider shared
      libraries when searching.
    """

    self.name = 'giflib'
    header = 'gif_lib.h'

    candidates = find_header(header)

    if not candidates:
André Anjos's avatar
André Anjos committed
272
      raise RuntimeError("could not find %s's `%s' - have you installed %s on this machine?" % (self.name, header, self.name))
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287

    found = False

    if not requirement:
      self.include_directory = os.path.dirname(candidates[0])
      self.version = libgif_version(candidates[0])
      found = True

    else:

      # requirement is 'operator' 'version'
      operator, required = [k.strip() for k in requirement.split(' ', 1)]

      # now check for user requirements
      for candidate in candidates:
288 289
        vv = libgif_version(candidate)
        available = LooseVersion(vv)
290 291 292 293 294 295
        if (operator == '<' and available < required) or \
           (operator == '<=' and available <= required) or \
           (operator == '>' and available > required) or \
           (operator == '>=' and available >= required) or \
           (operator == '==' and available == required):
          self.include_directory = os.path.dirname(candidate)
296
          self.version = vv
297 298 299 300
          found = True
          break

    if not found:
André Anjos's avatar
André Anjos committed
301
      raise RuntimeError("could not find the required (%s) version of %s on the file system (looked at: %s)" % (requirement, self.name, ', '.join(candidates)))
302 303 304 305 306 307 308 309 310 311

    # normalize
    self.include_directory = os.path.normpath(self.include_directory)

    # find library
    prefix = os.path.dirname(os.path.dirname(self.include_directory))
    module = 'gif'
    candidates = find_library(module, version=self.version, prefixes=[prefix], only_static=only_static)

    if not candidates:
312
      raise RuntimeError("cannot find required %s binary module `%s' - make sure `%s' is installed on `%s'" % (self.name, module, self.name, prefix))
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331

    # libraries
    self.libraries = []
    name, ext = os.path.splitext(os.path.basename(candidates[0]))
    if ext in ['.so', '.a', '.dylib', '.dll']:
      self.libraries.append(name[3:]) #strip 'lib' from the name
    else: #link against the whole thing
      self.libraries.append(':' + os.path.basename(candidates[0]))

    # library path
    self.library_directory = os.path.dirname(candidates[0])

  def macros(self):
    return [
        ('HAVE_%s' % self.name.upper(), '1'),
        ('%s_VERSION' % self.name.upper(), '"%s"' % self.version),
        ]

jpeg_pkg = jpeg()
André Anjos's avatar
André Anjos committed
332
tiff_pkg = tiff()
333 334
gif_pkg = gif()

335 336 337 338
system_include_dirs = [
    jpeg_pkg.include_directory,
    tiff_pkg.include_directory,
    gif_pkg.include_directory,
339 340 341 342
    ]

library_dirs = [
    jpeg_pkg.library_directory,
André Anjos's avatar
André Anjos committed
343
    tiff_pkg.library_directory,
344 345 346 347 348
    gif_pkg.library_directory,
    ]

libraries = \
    jpeg_pkg.libraries + \
André Anjos's avatar
André Anjos committed
349
    tiff_pkg.libraries + \
Amir Mohammadi's avatar
Amir Mohammadi committed
350
    gif_pkg.libraries
351 352 353

define_macros = \
    jpeg_pkg.macros() + \
André Anjos's avatar
André Anjos committed
354
    tiff_pkg.macros() + \
Amir Mohammadi's avatar
Amir Mohammadi committed
355
    gif_pkg.macros()
356

André Anjos's avatar
André Anjos committed
357 358
setup(

André Anjos's avatar
André Anjos committed
359
    name='bob.io.image',
André Anjos's avatar
André Anjos committed
360 361
    version=version,
    description='Image I/O support for Bob',
André Anjos's avatar
André Anjos committed
362
    url='http://gitlab.idiap.ch/bob/bob.io.image',
André Anjos's avatar
André Anjos committed
363 364 365 366 367 368 369 370
    license='BSD',
    author='Andre Anjos',
    author_email='andre.anjos@idiap.ch',

    long_description=open('README.rst').read(),

    packages=find_packages(),
    include_package_data=True,
André Anjos's avatar
André Anjos committed
371
    zip_safe=False,
André Anjos's avatar
André Anjos committed
372

373 374
    setup_requires = build_requires,
    install_requires = build_requires,
André Anjos's avatar
André Anjos committed
375 376

    ext_modules = [
André Anjos's avatar
André Anjos committed
377
      Extension("bob.io.image.version",
André Anjos's avatar
André Anjos committed
378
        [
André Anjos's avatar
André Anjos committed
379
          "bob/io/image/version.cpp",
380
        ],
André Anjos's avatar
André Anjos committed
381
        packages = packages,
382
        boost_modules = boost_modules,
383
        bob_packages = bob_packages,
André Anjos's avatar
André Anjos committed
384
        version = version,
385
        system_include_dirs = system_include_dirs,
386 387 388
        library_dirs = library_dirs,
        libraries = libraries,
        define_macros = define_macros,
389 390
      ),

391
      Library("bob.io.image.bob_io_image",
André Anjos's avatar
André Anjos committed
392
        [
393 394 395 396 397 398 399
          "bob/io/image/cpp/tiff.cpp",
          "bob/io/image/cpp/gif.cpp",
          "bob/io/image/cpp/png.cpp",
          "bob/io/image/cpp/jpeg.cpp",
          "bob/io/image/cpp/bmp.cpp",
          "bob/io/image/cpp/pnmio.cpp",
          "bob/io/image/cpp/netpbm.cpp",
400
          "bob/io/image/cpp/image.cpp",
401 402 403 404 405 406 407 408 409 410 411 412 413
        ],
        packages = packages,
        boost_modules = boost_modules,
        bob_packages = bob_packages,
        version = version,
        system_include_dirs = system_include_dirs,
        library_dirs = library_dirs,
        libraries = libraries,
        define_macros = define_macros,
      ),

      Extension("bob.io.image._library",
        [
André Anjos's avatar
André Anjos committed
414
          "bob/io/image/main.cpp",
415
        ],
André Anjos's avatar
André Anjos committed
416
        packages = packages,
417
        boost_modules = boost_modules,
418
        bob_packages = bob_packages,
André Anjos's avatar
André Anjos committed
419
        version = version,
420
        system_include_dirs = system_include_dirs,
421 422 423
        library_dirs = library_dirs,
        libraries = libraries,
        define_macros = define_macros,
424
      ),
425 426 427 428 429 430 431 432 433 434 435 436 437 438

      Extension("bob.io.image._test",
        [
          "bob/io/image/test.cpp",
        ],
        packages = packages,
        boost_modules = boost_modules,
        bob_packages = bob_packages,
        version = version,
        system_include_dirs = system_include_dirs,
        library_dirs = library_dirs,
        libraries = libraries,
        define_macros = define_macros,
      ),
439
    ],
André Anjos's avatar
André Anjos committed
440

441

442 443 444 445
    cmdclass = {
      'build_ext': build_ext
    },

André Anjos's avatar
André Anjos committed
446
    classifiers = [
447 448
      'Framework :: Bob',
      'Development Status :: 4 - Beta',
André Anjos's avatar
André Anjos committed
449 450 451 452 453 454 455
      'Intended Audience :: Developers',
      'License :: OSI Approved :: BSD License',
      'Natural Language :: English',
      'Programming Language :: Python',
      'Programming Language :: Python :: 3',
      'Topic :: Software Development :: Libraries :: Python Modules',
      'Environment :: Plugins',
456
    ],
André Anjos's avatar
André Anjos committed
457

458
)