[Distutils] install_headers,install_data

Rene Liebscher R.Liebscher@gmx.de
Thu, 08 Jun 2000 19:05:09 +0200


This is a multi-part message in MIME format.
--------------619C704BE9D2B60BEEDC9A1A
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi,

when I tried to build a binary distribution
I found that there were no headers in it.
(But a normal install worked.)
Also I found bdist_rpm didn't work with
headers and data files.

There were two problems:
Someone simply forgot the headers in the
install command.

From install_headers and install_data
you couldn't get the copied files (outfiles.)
(rpm seems to use it.)


And here is now a patch which solves both
problems.


Shouldn't header files be installed in
/usr/local/python1.5/include 
instead of
/usr/local/python/1.5/include ?

Another problem is that MANIFEST
is build from two sources.

MANIFEST.in
                         > MANIFEST
parameters of setup()

If someone changes the parameter of setup()
the MANIFEST file should be rebuild.

The best way to do so is to check the date
of file sys.argv[0], in almost all cases
setup() is called from there. It is also
included in this patch.


Kind regards

Rene Liebscher

PS: I send the last version of my cygwin-compiler
class with this mail.  If someone wants to try it,
simply copy it in the commands directory. (The
compiler mapping is already inserted 
in the current cvs version.)
--------------619C704BE9D2B60BEEDC9A1A
Content-Type: text/plain; charset=us-ascii;
 name="install.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="install.patch"

diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/command/install.py distutils.patched/distutils/command/install.py
--- distutils.orig/distutils/command/install.py	Tue Jun  6 11:17:05 2000
+++ distutils.patched/distutils/command/install.py	Thu Jun  8 18:10:13 2000
@@ -18,7 +18,7 @@
     'unix_prefix': {
         'purelib': '$base/lib/python$py_version_short/site-packages',
         'platlib': '$platbase/lib/python$py_version_short/site-packages',
-        'headers': '$base/include/python/$py_version_short/$dist_name',
+        'headers': '$base/include/python$py_version_short/$dist_name',
         'scripts': '$base/bin',
         'data'   : '$base/share',
         },
@@ -272,7 +272,7 @@
         # If a new root directory was supplied, make all the installation
         # dirs relative to it.
         if self.root is not None:
-            for name in ('lib', 'purelib', 'platlib', 'scripts', 'data'):
+            for name in ('lib', 'purelib', 'platlib', 'scripts', 'data','headers'):
                 attr = "install_" + name
                 new_val = change_root (self.root, getattr (self, attr))
                 setattr (self, attr, new_val)
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/command/install_data.py distutils.patched/distutils/command/install_data.py
--- distutils.orig/distutils/command/install_data.py	Tue Jun  6 11:17:05 2000
+++ distutils.patched/distutils/command/install_data.py	Thu Jun  8 18:46:58 2000
@@ -25,7 +25,7 @@
 
     def initialize_options (self):
         self.install_dir = None
-        self.outfiles = None
+        self.outfiles = []
         self.root = None
         self.data_files = self.distribution.data_files
 
@@ -35,6 +35,13 @@
 				   ('root', 'root'),
 				  )
 
+    def copy_file(self,src,dst):	
+        # we need a list of our output files
+        if os.path.isdir (dst):
+            dst = os.path.join (dst, os.path.basename (src))
+        Command.copy_file(self,src,dst)
+        self.outfiles.append(dst)       
+
     def run (self):
         self.mkpath(self.install_dir)
         for f in self.data_files:
@@ -56,4 +63,4 @@
         return self.data_files or []
 
     def get_outputs (self):
-        return self.outfiles or []
+        return self.outfiles
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/command/install_headers.py distutils.patched/distutils/command/install_headers.py
--- distutils.orig/distutils/command/install_headers.py	Sat May 27 03:25:16 2000
+++ distutils.patched/distutils/command/install_headers.py	Thu Jun  8 18:47:07 2000
@@ -7,6 +7,7 @@
 
 __revision__ = "$Id: install_headers.py,v 1.1 2000/05/27 01:25:16 gward Exp $"
 
+import os
 from distutils.core import Command
 
 
@@ -21,11 +22,19 @@
 
     def initialize_options (self):
         self.install_dir = None
+	self.outfiles = []
 
     def finalize_options (self):
         self.set_undefined_options('install',
                                    ('install_headers', 'install_dir'))
 
+    def copy_file(self,src,dst):
+        # we need a list of our output files
+        if os.path.isdir (dst):
+            dst = os.path.join (dst, os.path.basename (src))
+        Command.copy_file(self,src,dst)
+        self.outfiles.append(dst)
+
     def run (self):
         headers = self.distribution.headers
         if not headers:
@@ -35,6 +44,11 @@
         for header in headers:
             self.copy_file(header, self.install_dir)
 
+    def get_inputs (self):
+        return self.distribution.headers or []
+
+    def get_outputs (self):
+        return self.outfiles
     # run()
 
 # class install_headers
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/command/sdist.py distutils.patched/distutils/command/sdist.py
--- distutils.orig/distutils/command/sdist.py	Thu Jun  8 17:35:23 2000
+++ distutils.patched/distutils/command/sdist.py	Thu Jun  8 18:10:13 2000
@@ -177,8 +177,16 @@
         if template_exists:
             template_newer = newer (self.template, self.manifest)
 
+        # some parts of MANIFEST result of parameters to the setup function call
+	# setup is probably called from the file which is sys.argv[0]
+	# so we check this dates too
+        manifest_exists = os.path.isfile (self.manifest)
+        if manifest_exists:
+            setup_py_newer = newer (sys.argv[0], self.manifest)
+
         # Regenerate the manifest if necessary (or if explicitly told to)
         if ((template_exists and template_newer) or
+	    (manifest_exists and setup_py_newer) or
             self.force_manifest or
             self.manifest_only):
 

--------------619C704BE9D2B60BEEDC9A1A
Content-Type: text/plain; charset=us-ascii;
 name="cygwinccompiler.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="cygwinccompiler.py"

"""distutils.cygwinccompiler

Contains the CygwinCCompiler class, a subclass of UnixCCompiler that handles
the Gnu Win32 C compiler.
It also contains the Mingw32CCompiler class which handles the mingw32 compiler
(same as cygwin in no-cygwin mode.)

"""

# created 2000/05/05, Rene Liebscher

__revision__ = "$Id: cygwinccompiler.py,v  $"

import os,sys,string,tempfile
from distutils import sysconfig
from distutils.unixccompiler import UnixCCompiler

# Because these compilers aren't configured in Python's config.h file by default
# we should at least warn the user if he used this unmodified version. 
def check_if_config_h_is_gcc_ready():
        """ checks, if the gcc-compiler is mentioned in config.h 
            if it is not, compiling probably doesn't work """ 
        from distutils import sysconfig
        import string,sys
        try:
                # It would probably better to read single lines to search.
                # But we do this only once, and it is fast enough 
                f=open(sysconfig.get_config_h_filename())
                s=f.read()
                f.close()
                try:
                        string.index(s,"__GNUC__") # is somewhere a #ifdef __GNUC__ or something similar
                except:
                        sys.stderr.write ("warning: Python's config.h doesn't seem to support your compiler.\n")
        except: # unspecific error => ignore
                pass


# This is called when the module is imported, so we make this check only once
check_if_config_h_is_gcc_ready()


# XXX Things not currently handled:
#   * see UnixCCompiler

class CygwinCCompiler (UnixCCompiler):

    compiler_type = 'cygwin'
   
    def __init__ (self,
                  verbose=0,
                  dry_run=0,
                  force=0):

        UnixCCompiler.__init__ (self, verbose, dry_run, force)

	# our compiler uses other names
	self.cc='gcc'
	self.ld_shared='dllwrap'
	self.ldflags_shared=[]

        # some variables to manage the differences between cygwin and mingw32
        self.dllwrap_options=["--target=i386-cygwin32"]
        # specification of entry point is not necessary
        
        self.dll_additional_libraries=[
               # cygwin shouldn't need msvcrt, but without the dll's will crash
               # perhaps something about initialization (Python uses it, too)
               # mingw32 needs it in all cases
                                        "msvcrt"
                                      ]
        
    # __init__ ()

    def link_shared_object (self,
                            objects,
                            output_filename,
                            output_dir=None,
                            libraries=None,
                            library_dirs=None,
                            runtime_library_dirs=None,
                            export_symbols=None,
			    debug=0,
                            extra_preargs=None,
                            extra_postargs=None):
        
        if libraries==None:
                libraries=[]
        
        python_library=["python"+str(sys.hexversion>>24)+str((sys.hexversion>>16)&0xff)]
        libraries=libraries+python_library+self.dll_additional_libraries
        
        # if you don't need the def-file afterwards, it is
        # better to use for it tempfile.mktemp() as its name
        # (unix-style compilers don't like backslashes in filenames)
        win_dll_def_file=string.replace(tempfile.mktemp(),"\\","/")
        #win_dll_def_file=output_filename[:-len(self.shared_lib_extension)]+".def"
        #win_dll_exp_file=output_filename[:-len(self.shared_lib_extension)]+".exp"
        #win_dll_lib_file=output_filename[:-len(self.shared_lib_extension)]+".a"
        
        # Make .def file
        # (It would probably better to check if we really need this, but for this we had to
        # insert some unchanged parts of UnixCCompiler, and this is not what I want.) 
        f=open(win_dll_def_file,"w")
        f.write("EXPORTS\n") # intro
        # always export a function "init"+module_name
        if not debug:
                f.write("init"+os.path.basename(output_filename)[:-len(self.shared_lib_extension)]+"\n")
        else: # in debug mode outfile_name is something like XXXXX_d.pyd
                f.write("init"+os.path.basename(output_filename)[:-(len(self.shared_lib_extension)+2)]+"\n")
        # if there are more symbols to export
        # insert code here to write them in f
        if export_symbols!=None: 
            for sym in export_symbols:
                f.write(sym+"\n")                
        f.close()
        
        if extra_preargs==None:
                extra_preargs=[]
        
        extra_preargs=extra_preargs+[
                        #"--verbose",
                        #"--output-exp",win_dll_exp_file,
                        #"--output-lib",win_dll_lib_file,
                        "--def",win_dll_def_file
                        ]+ self.dllwrap_options
        
        # who wants symbols and a many times greater output file
        # should explicitely switch the debug mode on 
        # otherwise we let dllwrap strip the outputfile
        # (On my machine unstripped_file=stripped_file+254KB
        #   10KB < stripped_file < ??100KB ) 
        if not debug: 
                extra_preargs=extra_preargs+["-s"] 
	
	try:        
    	    UnixCCompiler.link_shared_object(self,
                            objects,
                            output_filename,
                            output_dir,
                            libraries,
                            library_dirs,
                            runtime_library_dirs,
			    None, # export_symbols, we do this with our def-file 
                            debug,
                            extra_preargs,
                            extra_postargs)
        finally: 
    	    # we don't need the def-file anymore
    	    os.remove(win_dll_def_file) 
        
    # link_shared_object ()

# class CygwinCCompiler

# the same as cygwin plus some additional parameters
class Mingw32CCompiler (CygwinCCompiler):

    compiler_type = 'mingw32'

    def __init__ (self,
                  verbose=0,
                  dry_run=0,
                  force=0):

        CygwinCCompiler.__init__ (self, verbose, dry_run, force)

        self.ccflags = self.ccflags + ["-mno-cygwin"]
        self.dllwrap_options=[
                                # mingw32 doesn't really need 'target' 
                                # and cygwin too (it seems, it is enough
                                # to specify a different entry point)                
                                #"--target=i386-mingw32",
                                "--entry","_DllMain@12"
                                ]
        # no additional libraries need 
        # (only msvcrt, which is already added by CygwinCCompiler)

    # __init__ ()
                
# class Mingw32CCompiler

--------------619C704BE9D2B60BEEDC9A1A--