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.
Don't duplicate commands
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 26 try: 27 import scripts.config as config 28 except ImportError: 29 import config 30 31 import fnmatch 32 import subprocess 33 34 def cmd(name, *args): 35 """create string for command line""" 36 parts = [name] 37 38 try: 39 base = basestring 40 except NameError: 41 base = str 42 43 for item in args: 44 if isinstance(item, base): 45 parts.append(item) 46 elif isinstance(item, dict): 47 for param, value in item.items(): 48 if isinstance(value, base): 49 value = [value] 50 parts.extend('--{0} {1}'.format(param, v) for v in value) 51 else: 52 parts.extend(item) 53 54 cmd_parts = [] 55 for p in parts: 56 if isinstance(p, str): 57 cmd_parts += [p] 58 else: 59 cmd_parts += [p.decode("utf-8")] 60 61 return ' '.join(cmd_parts) 62 63 def get_sources_path (folder, pattern): 64 """obtain the path to all source files that matches pattern""" 65 files = [] 66 for root, dirnames, filenames in os.walk(folder): 67 for filename in fnmatch.filter(filenames, pattern): 68 files.append(os.path.join(root, filename)) 69 return files 70 71 72 73 def get_sources_name (folder, pattern): 74 """obtain name of all source files that matches pattern""" 75 files = [] 76 for root, dirnames, filenames in os.walk(folder): 77 for filename in fnmatch.filter(filenames, pattern): 78 files.append(filename) 79 return files 80 81 82 83 class Vala(object): 84 """helper to generate tasks to compile vala code""" 85 86 def __init__(self, src, build, pkg_libs, library=None, vala_deps=None, so_version=None): 87 self.src = src 88 self.build = build 89 self.pkg_libs = pkg_libs 90 self.vala_deps = vala_deps or [] 91 self.library = library 92 93 self.vala = get_sources_path (src, '*.vala') 94 self.c = get_sources_path (src, '*.c') # copy regular c sources 95 self.c += get_sources_path (src, '*.h') # copy header files for the c sources 96 self.cc = [join(build + '/' + src, f) for f in get_sources_name (src, '*.c') ] 97 self.cc += [join(build + '/' + src, f.replace('.vala', '.c')) for f in get_sources_name (src, '*.vala')] 98 self.obj = [self.build + '/' + self.src + '/' + f.replace('.c', '.o') for f in get_sources_name (src, '*.c')] 99 self.obj += [self.build + '/' + self.src + '/' + f.replace('.vala', '.o') for f in get_sources_name (src, '*.vala')] 100 101 if library: 102 self.header = join(build, library) + '.h' 103 self.vapi = join(build, library) + '.vapi' # generated vapi file 104 self.other_vapi_files = get_sources_path (src, '*.vapi') # other vapi files 105 self.so = join(build, src) + '.so.' + so_version 106 self.so_link = join(build, src) + '.so' 107 self.so_link_name = src + '.so' 108 self.so_version = so_version 109 self.so_name = 'lib' + library + '.so.' + so_version 110 else: 111 self.other_vapi_files = [] 112 113 def gen_c(self, opts): 114 """translate code from vala to C and create .vapi""" 115 options = ['--ccode'] 116 options.extend(opts) 117 params = { 118 'basedir': join(self.build, self.src), 119 'vapidir': './', 120 'pkg': self.pkg_libs, 121 } 122 if self.library: 123 params['library'] = self.library 124 params['vapi'] = self.vapi 125 params['header'] = self.header 126 127 dep_vapi = [d.vapi for d in self.vala_deps] 128 action = cmd('valac', options, params, dep_vapi, self.vala) 129 targets = self.cc[:] 130 131 if self.library: 132 targets += [self.header, self.vapi] 133 134 for f in self.c: 135 yield { 136 'name': 'copy_c_' + f, 137 'actions': [ 138 'mkdir -p '+ self.build + '/' + self.src + '/', 139 'cp ' + f + ' ' + self.build + '/' + self.src + '/' 140 ], 141 } 142 143 for f in self.other_vapi_files: 144 yield { 145 'name': 'vapi_files_' + f, 146 'actions': [ 147 'mkdir -p '+ self.build + '/', 148 'cp ' + f + ' ' + self.build + '/' 149 ], 150 } 151 152 print (action) 153 154 if not self.vala == []: 155 yield { 156 'name': 'compile_c', 157 'actions': [ action ], 158 'file_dep': self.vala + dep_vapi, 159 'targets': targets, 160 } 161 162 163 def gen_o(self, opts): 164 """compile C files to obj `.o` """ 165 def compile_cmd(conf, opts, libs, pos): 166 flags = [] 167 for l in libs: 168 if not l == "posix" and not l == "posixtypes": 169 process = subprocess.Popen ('pkg-config --cflags ' + l, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 170 cflags = process.stdout.readline() 171 process.communicate()[0] 172 if not process.returncode == 0: 173 print ( "Library not found: " + l) 174 exit (1) 175 flags += [cflags.strip ()] 176 177 return cmd(config.CC, opts, flags, pos) 178 179 for cc, obj in zip(self.cc, self.obj): 180 pos = ["-c " + cc, "-o " + obj ] 181 cmd_args = {'libs':self.pkg_libs, 'opts':opts, 'pos':pos} 182 action = CmdAction((compile_cmd, [], cmd_args)) 183 184 yield { 185 'name': obj.rsplit('/')[-1], 186 'file_dep': [ cc ], 187 'actions': [ action ], 188 'getargs': { 'conf': ('pkg_flags', 'out') }, 189 'targets': [ obj ], 190 } 191 192 193 def gen_so(self, generated_libs = None): 194 """generate ".so" lib file""" 195 def compile_cmd(conf, libs): 196 obj_glob = join(self.build, self.src, '*.o') 197 opts = ['-shared ' 198 + '-Wl,-soname,' + self.so_name 199 + ' ' + obj_glob 200 + ' -o ' + self.so ] 201 202 flags = [] 203 for l in libs: 204 if not l == "posix" and not l == "posixtypes": 205 process = subprocess.Popen ('pkg-config --cflags ' + l, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 206 cflags = process.stdout.readline() 207 process.communicate()[0] 208 if not process.returncode == 0: 209 print ( "Library not found: " + l) 210 exit (1) 211 flags += [cflags.strip ()] 212 213 if generated_libs: 214 flags += [generated_libs] 215 216 return cmd(config.CC, opts, flags) 217 218 return { 219 'name': self.so.rsplit('/')[-1], 220 'actions': [ CmdAction((compile_cmd, [], {'libs':self.pkg_libs})) ], 221 'getargs': { 'conf': ('pkg_flags', 'out') }, 222 'file_dep': self.obj, 223 'targets': [ self.so ], 224 } 225 226 def gen_ln(self): 227 """generate a symbolic link to the generated ".so" file""" 228 so_file = self.so.rsplit('/')[-1] 229 230 if not "bsd" in sys.platform or "kfreebsd" in sys.platform: 231 create_link = "ln -s -T " + so_file + " " + self.so_link_name + " " 232 233 create_link += "&& mv " + self.so_link_name + " " + self.build + "/" 234 return { 235 'name': self.so_link_name, 236 'actions': [ create_link], 237 'file_dep': [ self.so ], 238 'targets': [ self.so_link ], 239 } 240 241 def gen_bin(self, opts): 242 """generate binary""" 243 def compile_cmd(conf, opts, libs): 244 flags = [conf[l].strip() for l in libs] 245 return cmd(config.CC, opts, flags) 246 247 bin_path = join(self.build, 'bin') 248 target = join(bin_path, self.src) 249 opts = (self.cc + opts + 250 ['-o ' + target, '-I ' + self.build, '-L ' + self.build] + 251 ['-l ' + d.library for d in self.vala_deps]) 252 action = CmdAction((compile_cmd, [], {'opts':opts, 'libs':self.pkg_libs})) 253 yield { 254 'name': "bin", 255 'actions': [ 'mkdir -p %s' % bin_path, action ], 256 'getargs': { 'conf': ('pkg_flags', 'out') }, 257 'file_dep': self.cc + [ d.so_link for d in self.vala_deps ], 258 'targets': [ target ], 259 } 260 261 262 263 264