- core.py
def setup (**attrs): dist.run_commands()
- dist.py
def run_commands (self): for cmd in self.commands: self.run_command(cmd)
- cmd.py
def run_command (self, command): """Run some other command: uses the 'run_command()' method of Distribution, which creates and finalizes the command object if necessary and then invokes its 'run()' method. """ self.distribution.run_command(command)
- dist.py
def run_command (self, command): """Do whatever it takes to run a command (including nothing at all, if the command has already been run). Specifically: if we have already created and run the command named by 'command', return silently without doing anything. If the command named by 'command' doesn't even have a command object yet, create one. Then invoke 'run()' on that command object (or an existing one). """ # Already been here, done that? then return silently. if self.have_run.get(command): return log.info("running %s", command) cmd_obj = self.get_command_obj(command) cmd_obj.ensure_finalized() cmd_obj.run() self.have_run[command] = 1
- cmd.py コメントにあるとおり、サブクラスではメソッドrunを実装している。
# Subclasses must define: # initialize_options() # provide default values for all options; may be customized by # setup script, by options from config file(s), or by command-line # options # finalize_options() # decide on the final values for all options; this is called # after all possible intervention from the outside world # (command-line, option file, etc.) has been processed # run() # run the command: do whatever it is we're here to do, # controlled by the command's various option values
- install.py
def run (self): # Obviously have to build before we can install if not self.skip_build: self.run_command('build') # Run all sub-commands (at least those that need to be run) for cmd_name in self.get_sub_commands(): self.run_command(cmd_name)
- cmd.py (get_sub_commands)
def get_sub_commands (self): commands = [] for (cmd_name, method) in self.sub_commands: if method is None or method(self): commands.append(cmd_name) return commands
- build.py sub_commandはclass変数として定義されている。
sub_commands = [('build_py', has_pure_modules), ('build_clib', has_c_libraries), ('build_ext', has_ext_modules), ('build_scripts', has_scripts), ]
- build_ext.py subcommandの一例として、build_extを追ってみる。
def run (self): ...skip... self.compiler = new_compiler(compiler=self.compiler, verbose=self.verbose, dry_run=self.dry_run, force=self.force) customize_compiler(self.compiler) ...skip... # Now actually compile and link everything. self.build_extensions() def build_extensions(self): # First, sanity-check the 'extensions' list self.check_extensions_list(self.extensions) for ext in self.extensions: self.build_extension(ext) def build_extension(self, ext): ...skip... objects = self.compiler.compile(sources, ...skip self.compiler.link_shared_object(
- ccompiler.py はcコンパイラの抽象。_compileとlinkをsubclassで実装する。
def compile(self, sources, output_dir=None, macros=None, def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): --> empty def link (self, --> empty def spawn (self, cmd): spawn (cmd, dry_run=self.dry_run) --> from distutils.spawn import spawn
- unixccompiler.py posix系はこのsubclassで実装されている。
def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): try: self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + extra_postargs) except DistutilsExecError, msg: raise CompileError, msg def link(self, target_desc, objects, self.spawn(linker + ld_args)
- spawn.py まあ当然ですが、forkに落ちます。
def _spawn_posix (cmd, pid = os.fork()
- build.pyでsub_commandのmappingを定義していたが、そのペアの右側はbuildのメソッドであり、distのmethodに転送される。。なので、このmethodがtrueを返すと、sub_commandが実行される。
build.py
def has_scripts (self): return self.distribution.has_scripts()
dist.py
def has_scripts (self): return self.scripts and len(self.scripts) > 0
- ではこのscriptsはどこからきているかというとsetupの**attrからきている。
core.py
def setup (**attrs): _setup_distribution = dist = klass(attrs)
dist.py
class Distribution: def __init__ (self, attrs=None): if attrs: for (key,val) in attrs.items(): if hasattr(self.metadata, key): setattr(self.metadata, key, val) elif hasattr(self, key): setattr(self, key, val) else: msg = "Unknown distribution option: %s" % repr(key) if warnings is not None: warnings.warn(msg) else: sys.stderr.write(msg + "\n")
2010年2月20日土曜日
distutils.buildを理解する。
大筋でどのようにできているかというと、setupは、distributionを表現するdistがあって、実際の生成プロセスを記述するcommandとsubcommandからなっている。次に関係ないところをすっ飛ばして引用してみた。
登録:
コメントの投稿 (Atom)
0 件のコメント:
コメントを投稿