1# 2# 3# Licensed to the Apache Software Foundation (ASF) under one 4# or more contributor license agreements. See the NOTICE file 5# distributed with this work for additional information 6# regarding copyright ownership. The ASF licenses this file 7# to you under the Apache License, Version 2.0 (the 8# "License"); you may not use this file except in compliance 9# with the License. You may obtain a copy of the License at 10# 11# http://www.apache.org/licenses/LICENSE-2.0 12# 13# Unless required by applicable law or agreed to in writing, 14# software distributed under the License is distributed on an 15# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16# KIND, either express or implied. See the License for the 17# specific language governing permissions and limitations 18# under the License. 19# 20# 21# 22# gen_make.py -- generate makefiles and dependencies 23# 24 25import os 26import stat 27import sys 28try: 29 # Python >=3.0 30 import configparser 31except ImportError: 32 # Python <3.0 33 import ConfigParser as configparser 34 35if sys.version_info[0] >= 3: 36 # Python >=3.0 37 from io import StringIO 38else: 39 # Python <3.0 40 try: 41 from cStringIO import StringIO 42 except ImportError: 43 from StringIO import StringIO 44 45import ezt 46 47import gen_base 48import generator.swig.header_wrappers 49import generator.swig.checkout_swig_header 50import generator.swig.external_runtime 51 52from gen_base import build_path_join, build_path_strip, build_path_splitfile, \ 53 build_path_basename, build_path_dirname, build_path_retreat, unique 54 55 56def _normstr(x): 57 if os.sep == '/': 58 return os.path.normpath(str(x)) 59 else: 60 return os.path.normpath(str(x).replace('/', os.sep)).replace(os.sep, '/') 61 62class Generator(gen_base.GeneratorBase): 63 64 _extension_map = { 65 ('exe', 'target'): '$(EXEEXT)', 66 ('exe', 'object'): '.lo', 67 ('lib', 'target'): '.la', 68 ('lib', 'object'): '.lo', 69 ('pyd', 'target'): '.la', 70 ('pyd', 'object'): '.lo', 71 ('so', 'target'): '.la', 72 ('so', 'object'): '.lo', 73 } 74 75 def __init__(self, fname, verfname, options=None): 76 gen_base.GeneratorBase.__init__(self, fname, verfname, options) 77 self.assume_shared_libs = False 78 if ('--assume-shared-libs', '') in options: 79 self.assume_shared_libs = True 80 81 def write(self): 82 install_deps = self.graph.get_deps(gen_base.DT_INSTALL) 83 install_sources = self.graph.get_all_sources(gen_base.DT_INSTALL) 84 85 cp = configparser.ConfigParser() 86 cp.read('gen-make.opts') 87 if cp.has_option('options', '--installed-libs'): 88 self.installed_libs = cp.get('options', '--installed-libs').split(',') 89 else: 90 self.installed_libs = [] 91 92 # ensure consistency between runs 93 install_deps.sort() 94 install_sources.sort(key = lambda s: s.name) 95 96 class _eztdata(object): 97 def __init__(self, **kw): 98 vars(self).update(kw) 99 100 data = _eztdata( 101 modules=[ ], 102 swig_langs=[ ], 103 swig_c=[ ], 104 target=[ ], 105 itargets=[ ], 106 areas=[ ], 107 isources=[ ], 108 deps=[ ], 109 sql=[], 110 ) 111 112 ######################################## 113 114 for target in install_sources: 115 if isinstance(target, gen_base.TargetRaModule) or \ 116 isinstance(target, gen_base.TargetFsModule): 117 # name of the module: strip 'libsvn_' and upper-case it 118 name = target.name[7:].upper() 119 120 # construct a list of the other .la libs to link against 121 retreat = build_path_retreat(target.path) 122 if target.name in self.installed_libs: 123 deps = [] 124 link = [ '-l%s-%s' % (target.name[3:], self.version) ] 125 else: 126 deps = [ target.filename ] 127 link = [ build_path_join(retreat, target.filename) ] 128 for source in self.graph.get_sources(gen_base.DT_LINK, target.name): 129 if not isinstance(source, gen_base.TargetLib) or source.external_lib: 130 continue 131 elif source.name in self.installed_libs: 132 continue 133 deps.append(source.filename) 134 link.append(build_path_join(retreat, source.filename)) 135 136 data.modules.append(_eztdata(name=name, deps=deps, link=link)) 137 138 # write a list of directories in which things are built 139 # get all the test scripts' directories 140 script_dirs = list(map(build_path_dirname, self.scripts + self.bdb_scripts)) 141 142 # remove duplicate directories between targets and tests 143 build_dirs = unique(self.target_dirs + script_dirs + self.swig_dirs) 144 data.build_dirs = build_dirs 145 146 # write lists of test files 147 # deps = all, progs = not including those marked "testing = skip" 148 data.bdb_test_deps = self.bdb_test_deps + self.bdb_scripts 149 data.bdb_test_progs = self.bdb_test_progs + self.bdb_scripts 150 data.test_deps = self.test_deps + self.scripts 151 data.test_progs = self.test_progs + self.scripts 152 data.test_helpers = self.test_helpers 153 154 # write list of all manpages 155 data.manpages = self.manpages 156 157 # write a list of files to remove during "make clean" 158 cfiles = [ ] 159 for target in install_sources: 160 # .la files are handled by the standard 'clean' rule; clean all the 161 # other targets 162 if not isinstance(target, gen_base.TargetScript) \ 163 and not isinstance(target, gen_base.TargetProject) \ 164 and not isinstance(target, gen_base.TargetI18N) \ 165 and not isinstance(target, gen_base.TargetJava) \ 166 and not target.external_lib \ 167 and target.filename[-3:] != '.la': 168 cfiles.append(target.filename) 169 for script in self.scripts: 170 if script.endswith('.py'): 171 cfiles.append(script + 'c') 172 data.cfiles = sorted(cfiles) 173 174 # here are all the SQL files and their generated headers. the Makefile 175 # has an implicit rule for generating these, so there isn't much to do 176 # except to clean them out. we only do that for 'make extraclean' since 177 # these are included as part of the tarball. the files are transformed 178 # by gen-make, and developers also get a Make rule to keep them updated. 179 for hdrfile, sqlfile in sorted(self.graph.get_deps(gen_base.DT_SQLHDR), 180 key=lambda t: t[0]): 181 data.sql.append(_eztdata(header=hdrfile, source=sqlfile[0])) 182 183 data.release_mode = ezt.boolean(self.release_mode) 184 185 ######################################## 186 187 if not self.release_mode: 188 swig_rules = StringIO() 189 for swig in (generator.swig.header_wrappers, 190 generator.swig.checkout_swig_header, 191 generator.swig.external_runtime): 192 gen = swig.Generator(self.conf, "swig") 193 gen.write_makefile_rules(swig_rules) 194 195 data.swig_rules = swig_rules.getvalue() 196 197 ######################################## 198 199 # write dependencies and build rules for generated .c files 200 swig_c_deps = sorted(self.graph.get_deps(gen_base.DT_SWIG_C), 201 key=lambda t: t[0].filename) 202 203 swig_lang_deps = {} 204 for lang in self.swig.langs: 205 swig_lang_deps[lang] = [] 206 207 for objname, sources in swig_c_deps: 208 swig_lang_deps[objname.lang].append(str(objname)) 209 210 for lang in self.swig.langs: 211 data.swig_langs.append(_eztdata(name=lang, 212 short=self.swig.short[lang], 213 short_upper=self.swig.short[lang].upper(), 214 deps=swig_lang_deps[lang])) 215 216 ######################################## 217 218 if not self.release_mode: 219 for objname, sources in swig_c_deps: 220 data.swig_c.append(_eztdata(c_file=str(objname), 221 deps=list(map(str, sources)), 222 opts=self.swig.opts[objname.lang], 223 source=str(sources[0]))) 224 225 ######################################## 226 227 for target_ob in install_sources: 228 229 if isinstance(target_ob, gen_base.TargetScript): 230 # there is nothing to build 231 continue 232 233 target = target_ob.name 234 if isinstance(target_ob, gen_base.TargetJava): 235 path = target_ob.output_dir 236 else: 237 path = target_ob.path 238 239 retreat = build_path_retreat(path) 240 241 # get the source items (.o and .la) for the link unit 242 objects = [ ] 243 objdeps = [ ] 244 object_srcs = [ ] 245 headers = [ ] 246 header_classes = [ ] 247 header_class_filenames = [ ] 248 deps = [ ] 249 libs = [ ] 250 add_deps = target_ob.add_deps.split() 251 252 for link_dep in self.graph.get_sources(gen_base.DT_LINK, target_ob.name): 253 if isinstance(link_dep, gen_base.TargetJava): 254 deps.append(link_dep.name) 255 elif isinstance(link_dep, gen_base.TargetLinked): 256 if link_dep.external_lib: 257 libs.append(link_dep.external_lib) 258 elif link_dep.external_project: 259 # FIXME: This is a temporary workaround to fix build breakage 260 # expeditiously. It is of questionable validity for a build 261 # node to have external_project but not have external_lib. 262 pass 263 elif link_dep.name in self.installed_libs: 264 libs.append('-l%s-%s' % (link_dep.name[3:], self.version)) 265 else: 266 # append the output of the target to our stated dependencies 267 if not self.assume_shared_libs: 268 deps.append(link_dep.filename) 269 270 # link against the library 271 libs.append(build_path_join(retreat, link_dep.filename)) 272 elif isinstance(link_dep, gen_base.ObjectFile): 273 # link in the object file 274 objects.append(link_dep.filename) 275 objdeps.append(_normstr(link_dep.filename)) 276 for dep in self.graph.get_sources(gen_base.DT_OBJECT, link_dep, gen_base.SourceFile): 277 object_srcs.append( 278 build_path_join('$(abs_srcdir)', dep.filename)) 279 elif isinstance(link_dep, gen_base.HeaderFile): 280 # link in the header file 281 # N.B. that filename_win contains the '_'-escaped class name 282 headers.append(link_dep.filename_win) 283 header_classes.append(link_dep.classname) 284 for dep in self.graph.get_sources(gen_base.DT_OBJECT, link_dep, gen_base.ObjectFile): 285 header_class_filenames.append(dep.filename) 286 else: 287 ### we don't know what this is, so we don't know what to do with it 288 raise UnknownDependency 289 290 for nonlib in self.graph.get_sources(gen_base.DT_NONLIB, target_ob.name): 291 if isinstance(nonlib, gen_base.TargetLinked): 292 if not nonlib.external_lib: 293 deps.append(nonlib.filename) 294 295 targ_varname = target.replace('-', '_') 296 objnames = build_path_strip(path, objects) 297 298 ezt_target = _eztdata(name=target_ob.name, 299 varname=targ_varname, 300 path=path, 301 install=None, 302 add_deps=add_deps, 303 objects=objects, 304 objdeps=objdeps, 305 deps=deps, 306 when=target_ob.when, 307 ) 308 data.target.append(ezt_target) 309 310 if hasattr(target_ob, 'link_cmd'): 311 ezt_target.link_cmd = target_ob.link_cmd 312 if hasattr(target_ob, 'output_dir'): 313 ezt_target.output_dir = target_ob.output_dir 314 if hasattr(target_ob, 'headers_dir'): 315 ezt_target.headers_dir = target_ob.headers_dir 316 317 # Add additional install dependencies if necessary 318 if target_ob.add_install_deps: 319 ezt_target.install = target_ob.install 320 ezt_target.install_deps = target_ob.add_install_deps 321 322 if isinstance(target_ob, gen_base.TargetJava): 323 ezt_target.type = 'java' 324 ezt_target.headers = headers 325 ezt_target.sources = None 326 ezt_target.jar = None 327 ezt_target.classes = target_ob.classes 328 329 # Build the headers from the header_classes with one 'javah' call 330 if headers: 331 ezt_target.header_class_filenames = header_class_filenames 332 ezt_target.header_classes = header_classes 333 334 # Build the objects from the object_srcs with one 'javac' call 335 if object_srcs: 336 ezt_target.sources = object_srcs 337 338 # Once the bytecodes have been compiled up, we produce the 339 # JAR. 340 if target_ob.jar: 341 ezt_target.jar_path = build_path_join(target_ob.classes, 342 target_ob.jar) 343 ezt_target.packages = target_ob.packages 344 345 elif isinstance(target_ob, gen_base.TargetI18N): 346 ezt_target.type = 'i18n' 347 else: 348 ezt_target.type = 'n/a' 349 ezt_target.filename = target_ob.filename 350 ezt_target.path = path 351 if (isinstance(target_ob, gen_base.TargetLib) 352 and not target_ob.undefined_lib_symbols): 353 ezt_target.undefined_flag = '$(LT_NO_UNDEFINED)' 354 else: 355 ezt_target.undefined_flag = '' 356 ezt_target.libs = gen_base.unique(libs) 357 ezt_target.objnames = objnames 358 ezt_target.basename = build_path_basename(target_ob.filename) 359 360 ######################################## 361 362 for itype, i_targets in install_deps: 363 364 # perl bindings do their own thing, "swig-pl" target is 365 # already specified in Makefile.in 366 if itype == "swig-pl": 367 continue 368 369 outputs = [ ] 370 371 for t in i_targets: 372 if hasattr(t, 'filename'): 373 outputs.append(t.filename) 374 375 data.itargets.append(_eztdata(type=itype, outputs=outputs)) 376 377 ######################################## 378 379 # for each install group, write a rule to install its outputs 380 for area, inst_targets in install_deps: 381 382 # perl bindings do their own thing, "install-swig-pl" target is 383 # already specified in Makefile.in 384 if area == "swig-pl": 385 continue 386 387 # get the output files for these targets, sorted in dependency order 388 files = gen_base._sorted_files(self.graph, area) 389 390 ezt_area_type = (area == 'apache-mod' and 'mods-shared' or area) 391 ezt_area = _eztdata(type=ezt_area_type, files=[], extra_install=None) 392 393 def file_to_eztdata(file): 394 # cd to dirname before install to work around libtool 1.4.2 bug. 395 dirname, fname = build_path_splitfile(file.filename) 396 return _eztdata(mode=None, 397 dirname=dirname, fullname=file.filename, 398 filename=fname, when=file.when, 399 pc_fullname=None, 400 pc_installdir=None, 401 pc_install_fname=None,) 402 403 def apache_file_to_eztdata(file): 404 # cd to dirname before install to work around libtool 1.4.2 bug. 405 dirname, fname = build_path_splitfile(file.filename) 406 base, ext = os.path.splitext(fname) 407 name = base.replace('mod_', '') 408 return _eztdata(mode='apache-mod', 409 fullname=file.filename, dirname=dirname, 410 name=name, filename=fname, when=file.when) 411 412 if area != 'test' and area != 'bdb-test': 413 data.areas.append(ezt_area) 414 415 area_var = area.replace('-', '_') 416 upper_var = area_var.upper() 417 ezt_area.varname = area_var 418 ezt_area.uppervar = upper_var 419 420 for file in files: 421 if isinstance(file.target, gen_base.TargetApacheMod): 422 ezt_file = apache_file_to_eztdata(file) 423 else: 424 ezt_file = file_to_eztdata(file) 425 if area == 'locale': 426 lang, objext = os.path.splitext(ezt_file.filename) 427 installdir = ('$(DESTDIR)$(%sdir)/%s/LC_MESSAGES' 428 % (area_var, lang)) 429 ezt_file.installdir = installdir 430 ezt_file.objext = objext 431 else: 432 ezt_file.install_fname = build_path_join('$(%sdir)' % area_var, 433 ezt_file.filename) 434 435 # Install pkg-config files 436 if (isinstance(file.target, gen_base.TargetLib) and 437 ezt_file.fullname.startswith('subversion/libsvn_')): 438 ezt_file.pc_fullname = ezt_file.fullname.replace('-1.la', '.pc') 439 ezt_file.pc_installdir = '$(pkgconfig_dir)' 440 pc_install_fname = ezt_file.filename.replace('-1.la', '.pc') 441 ezt_file.pc_install_fname = build_path_join(ezt_file.pc_installdir, 442 pc_install_fname) 443 ezt_area.files.append(ezt_file) 444 445 # certain areas require hooks for extra install rules defined 446 # in Makefile.in 447 ### we should turn AREA into an object, then test it instead of this 448 if area[:5] == 'swig-' and area[-4:] != '-lib' \ 449 or area[:7] == 'javahl-' \ 450 or area[:6] == 'svnxx-' \ 451 or area == 'tools': 452 ezt_area.extra_install = 'yes' 453 454 ######################################## 455 456 includedir = build_path_join('$(includedir)', 457 'subversion-%s' % self.version) 458 data.includes = [_eztdata(file=file, 459 src=build_path_join('$(abs_srcdir)', file), 460 dst=build_path_join(includedir, 461 build_path_basename(file))) 462 for file in self.includes] 463 data.includedir = includedir 464 465 ######################################## 466 467 for target in install_sources: 468 if not isinstance(target, gen_base.TargetScript) and \ 469 not isinstance(target, gen_base.TargetJava) and \ 470 not isinstance(target, gen_base.TargetI18N): 471 data.isources.append(_eztdata(name=target.name, 472 filename=target.filename)) 473 474 ######################################## 475 476 # write dependencies and build rules (when not using suffix rules) 477 # for all other generated files which will not be installed 478 # (or will be installed, but not by the main generated build) 479 obj_deps = sorted(self.graph.get_deps(gen_base.DT_OBJECT), 480 key=lambda t: t[0].filename) 481 482 for objname, sources in obj_deps: 483 dep = _eztdata(name=_normstr(objname), 484 when=objname.when, 485 deps=list(map(_normstr, sources)), 486 cmd=objname.compile_cmd, 487 source=_normstr(sources[0])) 488 data.deps.append(dep) 489 dep.generated = ezt.boolean(getattr(objname, 'source_generated', 0)) 490 491 template = ezt.Template(os.path.join('build', 'generator', 'templates', 492 'build-outputs.mk.ezt'), 493 compress_whitespace=False) 494 template.generate(open('build-outputs.mk', 'w'), data) 495 496 self.write_standalone() 497 498 self.write_transform_libtool_scripts(install_sources) 499 500 self.write_pkg_config_dot_in_files(install_sources) 501 502 def write_standalone(self): 503 """Write autogen-standalone.mk""" 504 505 standalone = open("autogen-standalone.mk", "w") 506 standalone.write('# DO NOT EDIT -- AUTOMATICALLY GENERATED ' 507 'BY build/generator/gen_make.py\n') 508 standalone.write('# FROM build-outputs.mk\n') 509 standalone.write('abs_srcdir = %s\n' % os.getcwd()) 510 standalone.write('abs_builddir = %s\n' % os.getcwd()) 511 standalone.write('top_srcdir = .\n') 512 standalone.write('top_builddir = .\n') 513 standalone.write('SWIG = swig\n') 514 standalone.write('SWIG_PY_OPTS = -python -py3 -nofastunpack -modern\n') 515 standalone.write('PYTHON = ' + sys.executable + '\n') 516 standalone.write('\n') 517 standalone.write(open("build-outputs.mk","r").read()) 518 standalone.close() 519 520 def write_transform_libtool_scripts(self, install_sources): 521 """Write build/transform_libtool_scripts.sh""" 522 script = 'build/transform_libtool_scripts.sh' 523 fd = open(script, 'w') 524 fd.write('''#!/bin/sh 525# DO NOT EDIT -- AUTOMATICALLY GENERATED BY build/generator/gen_make.py 526 527transform() 528{ 529 SCRIPT="$1" 530 LIBS="$2" 531 if [ -f $SCRIPT ]; then 532 if grep LD_PRELOAD "$SCRIPT" > /dev/null; then 533 : 534 elif grep LD_LIBRARY_PATH "$SCRIPT" > /dev/null; then 535 echo "Transforming $SCRIPT" 536 EXISTINGLIBS="" 537 for LIB in $LIBS; do 538 # exclude libsvn_test since the undefined test_funcs breaks libtool 539 case $LIB in 540 *libsvn_test-*) continue ;; 541 esac 542 if [ ! -f $LIB ]; then 543 continue 544 fi 545 if [ -z "$EXISTINGLIBS" ]; then 546 EXISTINGLIBS="$LIB" 547 else 548 EXISTINGLIBS="$EXISTINGLIBS $LIB" 549 fi 550 done 551 if [ ! -z "$EXISTINGLIBS" ]; then 552 cat "$SCRIPT" | 553 ( 554 read LINE 555 echo "$LINE" 556 read LINE 557 echo "$LINE" 558 read LINE 559 echo "$LINE" 560 read LINE 561 echo "$LINE" 562 echo "LD_PRELOAD=\\"$EXISTINGLIBS\\"" 563 echo "export LD_PRELOAD" 564 cat 565 ) < "$SCRIPT" > "$SCRIPT.new" 566 mv -f "$SCRIPT.new" "$SCRIPT" 567 chmod +x "$SCRIPT" 568 fi 569 fi 570 fi 571} 572 573DIR=`pwd` 574 575''') 576 libdep_cache = {} 577 paths = {} 578 for lib in ('libsvn_auth_gnome_keyring', 'libsvn_auth_kwallet'): 579 paths[lib] = self.sections[lib].options.get('path') 580 for target_ob in install_sources: 581 if not isinstance(target_ob, gen_base.TargetExe): 582 continue 583 name = target_ob.name 584 libs = self._get_all_lib_deps(target_ob.name, libdep_cache, paths) 585 path = paths[name] 586 for i in range(0, len(libs)): 587 lib = libs[i] 588 libpath = paths[libs[i]] 589 libs[i] = '$DIR/%s/.libs/%s-%s.so' % (libpath, lib, self.version) 590 fd.write('transform %s/%s "%s"\n' % (path, name, " ".join(libs))) 591 fd.close() 592 mode = stat.S_IRWXU|stat.S_IRGRP|stat.S_IXGRP|stat.S_IROTH|stat.S_IXOTH 593 os.chmod(script, mode) 594 595 def _get_all_lib_deps(self, target_name, libdep_cache, paths): 596 if not target_name in libdep_cache: 597 libs = set() 598 path = None 599 if target_name in self.sections: 600 section = self.sections[target_name] 601 opt_libs = self.sections[target_name].options.get('libs') 602 paths[target_name] = section.options.get('path') 603 if opt_libs: 604 for lib_name in opt_libs.split(): 605 if lib_name.startswith('libsvn_'): 606 libs.add(lib_name) 607 for lib in self._get_all_lib_deps(lib_name, libdep_cache, paths): 608 libs.add(lib) 609 if target_name == 'libsvn_subr': 610 libs.update(('libsvn_auth_gnome_keyring', 'libsvn_auth_kwallet')) 611 libdep_cache[target_name] = sorted(libs) 612 return libdep_cache[target_name] 613 614 def write_pkg_config_dot_in_files(self, install_sources): 615 """Write pkg-config .pc.in files for Subversion libraries.""" 616 for target_ob in install_sources: 617 if not (isinstance(target_ob, gen_base.TargetLib) and 618 target_ob.path.startswith('subversion/libsvn_')): 619 continue 620 621 lib_name = target_ob.name 622 lib_path = self.sections[lib_name].options.get('path') 623 lib_deps = self.sections[lib_name].options.get('libs') 624 lib_desc = self.sections[lib_name].options.get('description') 625 output_path = build_path_join(lib_path, lib_name + '.pc.in') 626 template = ezt.Template(os.path.join('build', 'generator', 'templates', 627 'pkg-config.in.ezt'), 628 compress_whitespace=False) 629 class _eztdata(object): 630 def __init__(self, **kw): 631 vars(self).update(kw) 632 633 data = _eztdata( 634 lib_name=lib_name, 635 lib_desc=lib_desc, 636 lib_deps=[], 637 lib_required=[], 638 lib_required_private=[], 639 version=self.version, 640 ) 641 # libsvn_foo -> -lsvn_foo-1 642 data.lib_deps.append('-l%s-%s' % (lib_name.replace('lib', '', 1), data.version)) 643 for lib_dep in lib_deps.split(): 644 if lib_dep == 'apriconv': 645 # apriconv is part of apr-util, skip it 646 continue 647 external_lib = self.sections[lib_dep].options.get('external-lib') 648 if external_lib: 649 ### Some of Subversion's internal libraries can appear as external 650 ### libs to handle conditional compilation. Skip these for now. 651 if external_lib in ['$(SVN_RA_LIB_LINK)', '$(SVN_FS_LIB_LINK)']: 652 continue 653 # If the external library is known to support pkg-config, 654 # add it to the Required: or Required.private: section. 655 # Otherwise, add the external library to linker flags. 656 pkg_config = self.sections[lib_dep].options.get('pkg-config') 657 if pkg_config: 658 private = self.sections[lib_dep].options.get('pkg-config-private') 659 if private: 660 data.lib_required_private.append(pkg_config) 661 else: 662 data.lib_required.append(pkg_config) 663 else: 664 # $(EXTERNAL_LIB) -> @EXTERNAL_LIB@ 665 data.lib_deps.append('@%s@' % external_lib[2:-1]) 666 else: 667 data.lib_required_private.append(lib_dep) 668 669 template.generate(open(output_path, 'w'), data) 670 671class UnknownDependency(Exception): 672 "We don't know how to deal with the dependent to link it in." 673 pass 674 675### End of file. 676