📄 gen_base.py
字号:
## gen_base.py -- infrastructure for generating makefiles, dependencies, etc.#import osimport sysimport stringimport globimport reimport fileinputimport ConfigParserimport generator.swigimport getversiondef _warning(msg): sys.stderr.write("WARNING: %s\n" % msg)def _error(msg): sys.stderr.write("ERROR: %s\n" % msg) sys.exit(1)class GeneratorBase: # # Derived classes should define a class attribute named _extension_map. # This attribute should be a dictionary of the form: # { (target-type, file-type): file-extension ...} # # where: target-type is 'exe', 'lib', ... # file-type is 'target', 'object', ... # def __init__(self, fname, verfname, options=None): # Retrieve major version from the C header, to avoid duplicating it in # build.conf - it is required because some file names include it. try: vsn_parser = getversion.Parser() vsn_parser.search('SVN_VER_MAJOR', 'libver') self.version = vsn_parser.parse(verfname).libver except: raise GenError('Unable to extract version.') # Read options self.release_mode = None for opt, val in options: if opt == '--release': self.release_mode = 1 # Now read and parse build.conf parser = ConfigParser.ConfigParser() parser.read(fname) self.conf = build_path(os.path.abspath(fname)) self.sections = { } self.graph = DependencyGraph() # Allow derived classes to suppress certain configuration sections if not hasattr(self, 'skip_sections'): self.skip_sections = { } # The 'options' section does not represent a build target, # it simply contains global options self.skip_sections['options'] = None # Read in the global options self.includes = \ _collect_paths(parser.get('options', 'includes')) self.private_includes = \ _collect_paths(parser.get('options', 'private-includes')) self.private_built_includes = \ string.split(parser.get('options', 'private-built-includes')) self.apache_files = \ _collect_paths(parser.get('options', 'static-apache-files')) self.scripts = \ _collect_paths(parser.get('options', 'test-scripts')) self.bdb_scripts = \ _collect_paths(parser.get('options', 'bdb-test-scripts')) self.include_wildcards = \ string.split(parser.get('options', 'include-wildcards')) self.swig_lang = string.split(parser.get('options', 'swig-languages')) self.swig_dirs = string.split(parser.get('options', 'swig-dirs')) # SWIG Generator self.swig = generator.swig.Generator(self.conf, "swig") # Visual C++ projects - contents are either TargetProject instances, # or other targets with an external-project attribute. self.projects = [] # Lists of pathnames of various kinds self.test_deps = [] # Non-BDB dependent items to build for the tests self.test_progs = [] # Subset of the above to actually execute self.bdb_test_deps = [] # BDB-dependent items to build for the tests self.bdb_test_progs = [] # Subset of the above to actually execute self.target_dirs = [] # Directories in which files are built self.manpages = [] # Manpages # Collect the build targets parser_sections = parser.sections() parser_sections.sort() # Have a reproducible ordering for section_name in parser_sections: if self.skip_sections.has_key(section_name): continue options = {} for option in parser.options(section_name): options[option] = parser.get(section_name, option) type = options.get('type') target_class = _build_types.get(type) if not target_class: raise GenError('ERROR: unknown build type for ' + section_name) section = target_class.Section(target_class, section_name, options, self) self.sections[section_name] = section section.create_targets() # Compute intra-library dependencies for section in self.sections.values(): dependencies = (( DT_LINK, section.options.get('libs', "") ), ( DT_NONLIB, section.options.get('nonlibs', "") )) for dep_type, dep_names in dependencies: # Translate string names to Section objects dep_section_objects = [] for section_name in string.split(dep_names): if self.sections.has_key(section_name): dep_section_objects.append(self.sections[section_name]) # For each dep_section that this section declares a dependency on, # take the targets of this section, and register a dependency on # any 'matching' targets of the dep_section. # # At the moment, the concept of multiple targets per section is # employed only for the SWIG modules, which have 1 target # per language. Then, 'matching' means being of the same language. for dep_section in dep_section_objects: for target in section.get_targets(): self.graph.bulk_add(dep_type, target.name, dep_section.get_dep_targets(target)) def compute_hdrs(self): """Get a list of the header files""" all_includes = map(native_path, self.includes + self.private_includes) for d in unique(self.target_dirs): for wildcard in self.include_wildcards: hdrs = glob.glob(os.path.join(native_path(d), wildcard)) all_includes.extend(hdrs) return all_includes def compute_hdr_deps(self): """Compute the dependencies of each header file""" include_deps = IncludeDependencyInfo(self.compute_hdrs(), map(native_path, self.private_built_includes)) for objectfile, sources in self.graph.get_deps(DT_OBJECT): assert len(sources) == 1 source = sources[0] # Generated .c files must depend on all headers their parent .i file # includes if isinstance(objectfile, SWIGObject): swigsources = self.graph.get_sources(DT_SWIG_C, source) assert len(swigsources) == 1 ifile = swigsources[0] assert isinstance(ifile, SWIGSource) c_includes, swig_includes = \ include_deps.query_swig(native_path(ifile.filename)) for include_file in c_includes: self.graph.add(DT_OBJECT, objectfile, build_path(include_file)) for include_file in swig_includes: self.graph.add(DT_SWIG_C, source, build_path(include_file)) # Any non-swig C/C++ object must depend on the headers it's parent # .c or .cpp includes. Note that 'object' includes gettext .mo files, # Java .class files, and .h files generated from Java classes, so # we must filter here. elif isinstance(source, SourceFile) and \ os.path.splitext(source.filename)[1] in ('.c', '.cpp'): for include_file in include_deps.query(native_path(source.filename)): self.graph.add(DT_OBJECT, objectfile, build_path(include_file))class DependencyGraph: """Record dependencies between build items. See the DT_* values for the different dependency types. For each type, the target and source objects recorded will be different. They could be file names, Target objects, install types, etc. """ def __init__(self): self.deps = { } # type -> { target -> [ source ... ] } for dt in dep_types: self.deps[dt] = { } def add(self, type, target, source): if self.deps[type].has_key(target): self.deps[type][target].append(source) else: self.deps[type][target] = [ source ] def bulk_add(self, type, target, sources): if self.deps[type].has_key(target): self.deps[type][target].extend(sources) else: self.deps[type][target] = sources[:] def get_sources(self, type, target, cls=None): sources = self.deps[type].get(target, [ ]) if not cls: return sources filtered = [ ] for src in sources: if isinstance(src, cls): filtered.append(src) return filtered def get_all_sources(self, type): sources = [ ] for group in self.deps[type].values(): sources.extend(group) return sources def get_deps(self, type): return self.deps[type].items()# dependency typesdep_types = [ 'DT_INSTALL', # install areas. e.g. 'lib', 'base-lib' 'DT_OBJECT', # an object filename, depending upon .c filenames 'DT_SWIG_C', # a swig-generated .c file, depending upon .i filename(s) 'DT_LINK', # a libtool-linked filename, depending upon object fnames 'DT_NONLIB', # filename depends on object fnames, but isn't linked to them ]# create some variables for thesefor _dt in dep_types: # e.g. DT_INSTALL = 'DT_INSTALL' globals()[_dt] = _dtclass DependencyNode: def __init__(self, filename): self.filename = filename def __str__(self): return self.filenameclass ObjectFile(DependencyNode): def __init__(self, filename, compile_cmd = None): DependencyNode.__init__(self, filename) self.compile_cmd = compile_cmd self.source_generated = 0class SWIGObject(ObjectFile): def __init__(self, filename, lang): ObjectFile.__init__(self, filename) self.lang = lang self.lang_abbrev = lang_abbrev[lang] ### hmm. this is Makefile-specific self.compile_cmd = '$(COMPILE_%s_WRAPPER)' % string.upper(self.lang_abbrev) self.source_generated = 1class HeaderFile(DependencyNode): def __init__(self, filename, classname = None, compile_cmd = None): DependencyNode.__init__(self, filename) self.classname = classname self.compile_cmd = compile_cmdclass SourceFile(DependencyNode): def __init__(self, filename, reldir): DependencyNode.__init__(self, filename) self.reldir = reldirclass SWIGSource(SourceFile): def __init__(self, filename): SourceFile.__init__(self, filename, build_path_dirname(filename)) passlang_abbrev = { 'python' : 'py', 'perl' : 'pl', 'ruby' : 'rb', }lang_full_name = { 'python' : 'Python', 'perl' : 'Perl', 'ruby' : 'Ruby', }lang_utillib_suffix = { 'python' : 'py', 'perl' : 'perl', 'ruby' : 'ruby', } class Target(DependencyNode): "A build target is a node in our dependency graph." def __init__(self, name, options, gen_obj): self.name = name self.gen_obj = gen_obj self.desc = options.get('description') self.path = options.get('path', '') self.add_deps = options.get('add-deps', '') self.add_install_deps = options.get('add-install-deps', '') self.msvc_name = options.get('msvc-name') # override project name def add_dependencies(self): # subclasses should override to provide behavior, as appropriate raise NotImplementedError class Section: """Represents an individual section of build.conf The Section class is sort of a factory class which is responsible for creating and keeping track of Target instances associated with a section of the configuration file. By default it only allows one Target per section, but subclasses may create multiple Targets. """ def __init__(self, target_class, name, options, gen_obj): self.target_class = target_class self.name = name self.options = options self.gen_obj = gen_obj def create_targets(self): """Create target instances""" self.target = self.target_class(self.name, self.options, self.gen_obj) self.target.add_dependencies() def get_targets(self): """Return list of target instances associated with this section""" return [self.target] def get_dep_targets(self, target): """Return list of targets from this section that "target" depends on""" return [self.target]class TargetLinked(Target): "The target is linked (by libtool) against other libraries." def __init__(self, name, options, gen_obj): Target.__init__(self, name, options, gen_obj) self.install = options.get('install') self.compile_cmd = options.get('compile-cmd') self.sources = options.get('sources', '*.c') self.link_cmd = options.get('link-cmd', '$(LINK)') self.external_lib = options.get('external-lib') self.external_project = options.get('external-project') self.msvc_libs = string.split(options.get('msvc-libs', '')) def add_dependencies(self): if self.external_lib or self.external_project: if self.external_project:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -