xmpedit

GTK+ editor for XMP metadata embedded in images
git clone https://code.djc.id.au/git/xmpedit/

build (6070B) - raw

      1 #!/usr/bin/env python3
      2 
      3 """
      4 My own homegrown build script.
      5 Because waf, SCons, autotools, and CMake all made me angry.
      6 """
      7 
      8 import sys
      9 import os
     10 import subprocess
     11 import errno
     12 
     13 def invoke(command):
     14     print(' '.join(command))
     15     subprocess.check_call(command)
     16 
     17 def files_under(*paths):
     18     result = []
     19     for path in paths:
     20         for dirpath, dirnames, filenames in os.walk(path):
     21             result.extend(os.path.join(dirpath, filename) for filename in filenames)
     22     return result
     23 
     24 def ensure_dir(path):
     25     if not os.path.isdir(path):
     26         os.makedirs(path)
     27 
     28 def replace_ext(path, old, new):
     29     if not path.endswith(old):
     30         raise ValueError('Path %r does not end with %r' % (path, old))
     31     return path[:-len(old)] + new
     32 
     33 class Program(object):
     34 
     35     default_valac = 'valac'
     36     default_vala_flags = '-g'
     37     default_cc = 'gcc'
     38     default_c_flags = '-g -O -Wall'
     39     default_cpp_flags = '-g -O -Wall'
     40     default_ld_flags = ''
     41 
     42     def __init__(self, target):
     43         self.target = target
     44         self.work_dir = os.path.join('target', '%s-work' % self.target)
     45         ensure_dir(self.work_dir)
     46         self.vala_sources = []
     47         self.valac = os.environ.get('VALAC', self.default_valac)
     48         self.vala_flags = os.environ.get('VALAFLAGS', self.default_vala_flags).split()
     49         self.vala_pkgs = []
     50         self.vala_vapidirs = []
     51         self.c_sources = []
     52         self.cc = os.environ.get('CC', self.default_cc)
     53         self.c_flags = os.environ.get('CFLAGS', self.default_c_flags).split()
     54         self.cpp_sources = []
     55         self.cpp_flags = os.environ.get('CXXFLAGS', self.default_cpp_flags).split()
     56         self.objects = []
     57         self.ld_flags = os.environ.get('LDFLAGS', self.default_ld_flags).split()
     58 
     59     def from_sources(self, vala_sources=[], c_sources=[], cpp_sources=[]):
     60         self.vala_sources.extend(vala_sources)
     61         self.c_sources.extend(c_sources)
     62         self.cpp_sources.extend(cpp_sources)
     63         return self
     64 
     65     def from_sources_under(self, *paths):
     66         self.vala_sources.extend(f for f in files_under(*paths) if f.endswith('.vala'))
     67         self.c_sources.extend(f for f in files_under(*paths) if f.endswith('.c'))
     68         self.cpp_sources.extend(f for f in files_under(*paths) if f.endswith('.cpp'))
     69         return self
     70 
     71     def with_vapi_dirs(self, *vapidirs):
     72         self.vala_flags.extend('--vapidir=%s' % vapidir for vapidir in vapidirs)
     73         return self
     74 
     75     def with_c_includes(self, *includes):
     76         self.c_flags.extend('-I%s' % inc for inc in includes)
     77         return self
     78 
     79     def with_cpp_includes(self, *includes):
     80         self.cpp_flags.extend('-I%s' % inc for inc in includes)
     81         return self
     82 
     83     def using_pkgs(self, *pkgs):
     84         for pkg in pkgs:
     85             cflags = subprocess.check_output(['pkg-config', '--cflags', pkg]).decode('ascii').split()
     86             self.c_flags.extend(cflags)
     87             self.cpp_flags.extend(cflags)
     88             self.ld_flags.extend(subprocess.check_output(['pkg-config', '--libs', pkg]).decode('ascii').split())
     89         self.vala_pkgs.extend(pkgs)
     90         return self
     91 
     92     def with_defines(self, *defs):
     93         self.vala_flags.extend('--define=%s' % d for d in defs)
     94         return self
     95 
     96     def build(self):
     97         self._compile_vala()
     98         self._compile_c()
     99         self._compile_cpp()
    100         self._link()
    101         
    102     def _compile_vala(self):
    103         if self.vala_sources:
    104             invoke([self.valac, '-C', '-d', self.work_dir] +
    105                    self.vala_flags +
    106                    ['--pkg=%s' % pkg for pkg in self.vala_pkgs] +
    107                    self.vala_sources)
    108             self.c_sources.extend(os.path.join(self.work_dir, replace_ext(source, '.vala', '.c'))
    109                     for source in self.vala_sources)
    110      
    111     def _compile_c(self):
    112         for source in self.c_sources:
    113             out = os.path.join(self.work_dir, replace_ext(os.path.basename(source), '.c', '.o'))
    114             invoke([self.cc] + self.c_flags + ['-c', source, '-o', out])
    115             self.objects.append(out)
    116      
    117     def _compile_cpp(self):
    118         for source in self.cpp_sources:
    119             out = os.path.join(self.work_dir, replace_ext(os.path.basename(source), '.cpp', '.o'))
    120             invoke(['g++'] + self.cpp_flags + ['-c', source, '-o', out])
    121             self.objects.append(out)
    122     
    123     def _link(self):
    124         invoke([self.cc] + self.ld_flags + self.objects +
    125                ['-o', os.path.join('target', self.target)])
    126 
    127 def compile():
    128     pkgs = ['gtk+-2.0', 'gee-1.0', 'libxml-2.0', 'libsoup-2.4', 'exiv2', 'osmgpsmap']
    129     xmpedit = Program('xmpedit') \
    130               .from_sources_under('src', 'lib') \
    131               .with_vapi_dirs('vapi') \
    132               .with_c_includes('src', 'lib/genx') \
    133               .using_pkgs(*pkgs) \
    134               .with_defines('DEBUG')
    135     xmpedit.c_flags.append('-Wno-pointer-sign')
    136     xmpedit.vala_pkgs.append('genx')
    137     xmpedit.build()
    138 
    139 def test():
    140     # unit tests
    141     pkgs = ['gtk+-2.0', 'gee-1.0', 'libxml-2.0', 'libsoup-2.4', 'exiv2', 'osmgpsmap']
    142     xmpedit_test = Program('xmpedit_test') \
    143                    .from_sources_under('src', 'lib') \
    144                    .with_vapi_dirs('vapi') \
    145                    .with_c_includes('src', 'lib/genx') \
    146                    .using_pkgs(*pkgs) \
    147                    .with_defines('DEBUG', 'TEST')
    148     xmpedit_test.c_flags.append('-Wno-pointer-sign')
    149     xmpedit_test.vala_pkgs.append('genx')
    150     xmpedit_test.build()
    151     invoke(['gtester', '--verbose', 'target/xmpedit_test'])
    152     # gui tests
    153     printxmp = Program('printxmp') \
    154                .from_sources(cpp_sources=[os.path.join('test', 'printxmp.cpp')]) \
    155                .using_pkgs('exiv2') \
    156                .build()
    157     invoke(['test/guitest.py'])
    158 
    159 if __name__ == '__main__':
    160     from optparse import OptionParser
    161     parser = OptionParser(usage='usage: %prog [options]')
    162     parser.add_option('-t', '--test', action='store_true', default=False,
    163             help='build and run tests')
    164     options, args = parser.parse_args()
    165     compile()
    166     if options.test:
    167         test()