The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

bavala.py in scripts

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of scripts/bavala.py.
Build with doit3
1 """ 2 Copyright (C) 2012, 2013, 2014 Eduardo Naufel Schettino and Johan Mattsson 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. 16 """ 17 18 """bavala is a build-tool for Vala that uses doit (http://pydoit.org)""" 19 20 import glob 21 import os 22 import sys 23 from os.path import join 24 from doit.action import CmdAction 25 import config 26 import fnmatch 27 import subprocess 28 29 def cmd(name, *args): 30 """create string for command line""" 31 parts = [name] 32 for item in args: 33 if isinstance(item, basestring): 34 parts.append(item) 35 elif isinstance(item, dict): 36 for param, value in item.iteritems(): 37 if isinstance(value, basestring): 38 value = [value] 39 parts.extend('--{0} {1}'.format(param, v) for v in value) 40 else: 41 parts.extend(item) 42 return ' '.join(parts) 43 44 45 def get_sources_path (folder, pattern): 46 """obtain the path to all source files that matches pattern""" 47 files = [] 48 for root, dirnames, filenames in os.walk(folder): 49 for filename in fnmatch.filter(filenames, pattern): 50 files.append(os.path.join(root, filename)) 51 return files 52 53 54 55 def get_sources_name (folder, pattern): 56 """obtain name of all source files that matches pattern""" 57 files = [] 58 for root, dirnames, filenames in os.walk(folder): 59 for filename in fnmatch.filter(filenames, pattern): 60 files.append(filename) 61 return files 62 63 64 65 class Vala(object): 66 """helper to generate tasks to compile vala code""" 67 68 def __init__(self, src, build, pkg_libs, library=None, vala_deps=None, so_version=None): 69 self.src = src 70 self.build = build 71 self.pkg_libs = pkg_libs 72 self.vala_deps = vala_deps or [] 73 self.library = library 74 75 self.vala = get_sources_path (src, '*.vala') 76 self.c = get_sources_path (src, '*.c') # copy regular c sources 77 self.c += get_sources_path (src, '*.h') # copy header files for the c sources 78 self.cc = [join(build + '/' + src, f) for f in get_sources_name (src, '*.c') ] 79 self.cc += [join(build + '/' + src, f.replace('.vala', '.c')) for f in get_sources_name (src, '*.vala')] 80 self.obj = [self.build + '/' + self.src + '/' + f.replace('.c', '.o') for f in get_sources_name (src, '*.c')] 81 self.obj += [self.build + '/' + self.src + '/' + f.replace('.vala', '.o') for f in get_sources_name (src, '*.vala')] 82 83 if library: 84 self.header = join(build, library) + '.h' 85 self.vapi = join(build, library) + '.vapi' # generated vapi file 86 self.other_vapi_files = get_sources_path (src, '*.vapi') # other vapi files 87 self.so = join(build, src) + '.so.' + so_version 88 self.so_link = join(build, src) + '.so' 89 self.so_link_name = src + '.so' 90 self.so_version = so_version 91 self.so_name = 'lib' + library + '.so.' + so_version 92 else: 93 self.other_vapi_files = [] 94 95 def gen_c(self, opts): 96 """translate code from vala to C and create .vapi""" 97 options = ['--ccode'] 98 options.extend(opts) 99 params = { 100 'basedir': join(self.build, self.src), 101 'vapidir': './', 102 'pkg': self.pkg_libs, 103 } 104 if self.library: 105 params['library'] = self.library 106 params['vapi'] = self.vapi 107 params['header'] = self.header 108 109 dep_vapi = [d.vapi for d in self.vala_deps] 110 action = cmd('valac', options, params, dep_vapi, self.vala) 111 targets = self.cc[:] 112 113 if self.library: 114 targets += [self.header, self.vapi] 115 116 for f in self.c: 117 yield { 118 'name': 'copy_c_' + f, 119 'actions': [ 120 'mkdir -p '+ self.build + '/' + self.src + '/', 121 'cp ' + f + ' ' + self.build + '/' + self.src + '/' 122 ], 123 } 124 125 for f in self.other_vapi_files: 126 yield { 127 'name': 'vapi_files_' + f, 128 'actions': [ 129 'mkdir -p '+ self.build + '/', 130 'cp ' + f + ' ' + self.build + '/' 131 ], 132 } 133 134 print (action) 135 136 if not self.vala == []: 137 yield { 138 'name': 'compile_c', 139 'actions': [ action ], 140 'file_dep': self.vala + dep_vapi, 141 'targets': targets, 142 } 143 144 145 def gen_o(self, opts): 146 """compile C files to obj `.o` """ 147 def compile_cmd(conf, opts, libs, pos): 148 flags = [] 149 for l in libs: 150 if not l == "posix" and not l == "posixtypes": 151 process = subprocess.Popen ('pkg-config --cflags ' + l, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 152 cflags = process.stdout.readline() 153 process.communicate()[0] 154 if not process.returncode == 0: 155 print ( "Library not found: " + l) 156 exit (1) 157 flags += [cflags.strip ()] 158 159 return cmd(config.CC, opts, flags, pos) 160 161 for cc, obj in zip(self.cc, self.obj): 162 pos = ["-c " + cc, "-o " + obj ] 163 cmd_args = {'libs':self.pkg_libs, 'opts':opts, 'pos':pos} 164 action = CmdAction((compile_cmd, [], cmd_args)) 165 166 yield { 167 'name': obj.rsplit('/')[-1], 168 'file_dep': [ cc ], 169 'actions': [ action ], 170 'getargs': { 'conf': ('pkg_flags', 'out') }, 171 'targets': [ obj ], 172 } 173 174 175 def gen_so(self, generated_libs = None): 176 """generate ".so" lib file""" 177 def compile_cmd(conf, libs): 178 obj_glob = join(self.build, self.src, '*.o') 179 opts = ['-shared ' 180 + '-Wl,-soname,' + self.so_name 181 + ' ' + obj_glob 182 + ' -o ' + self.so ] 183 184 flags = [] 185 for l in libs: 186 if not l == "posix" and not l == "posixtypes": 187 process = subprocess.Popen ('pkg-config --cflags ' + l, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 188 cflags = process.stdout.readline() 189 process.communicate()[0] 190 if not process.returncode == 0: 191 print ( "Library not found: " + l) 192 exit (1) 193 flags += [cflags.strip ()] 194 195 if generated_libs: 196 flags += [generated_libs] 197 198 return cmd(config.CC, opts, flags) 199 200 return { 201 'name': self.so.rsplit('/')[-1], 202 'actions': [ CmdAction((compile_cmd, [], {'libs':self.pkg_libs})) ], 203 'getargs': { 'conf': ('pkg_flags', 'out') }, 204 'file_dep': self.obj, 205 'targets': [ self.so ], 206 } 207 208 def gen_ln(self): 209 """generate a symbolic link to the generated ".so" file""" 210 so_file = self.so.rsplit('/')[-1] 211 create_link = "ln -s -T " + so_file + " " + self.so_link_name + " " 212 create_link += "&& mv " + self.so_link_name + " " + self.build + "/" 213 return { 214 'name': self.so_link_name, 215 'actions': [ create_link], 216 'file_dep': [ self.so ], 217 'targets': [ self.so_link ], 218 } 219 220 def gen_bin(self, opts): 221 """generate binary""" 222 def compile_cmd(conf, opts, libs): 223 flags = [conf[l].strip() for l in libs] 224 return cmd(config.CC, opts, flags) 225 226 bin_path = join(self.build, 'bin') 227 target = join(bin_path, self.src) 228 opts = (self.cc + opts + 229 ['-o ' + target, '-I ' + self.build, '-L ' + self.build] + 230 ['-l ' + d.library for d in self.vala_deps]) 231 action = CmdAction((compile_cmd, [], {'opts':opts, 'libs':self.pkg_libs})) 232 yield { 233 'name': "bin", 234 'actions': [ 'mkdir -p %s' % bin_path, action ], 235 'getargs': { 'conf': ('pkg_flags', 'out') }, 236 'file_dep': self.cc + [ d.so_link for d in self.vala_deps ], 237 'targets': [ target ], 238 } 239 240 241 242 243