[26461] users/pipping/merge.rb

Kevin Ballard eridius at macports.org
Sun Jun 24 22:22:57 PDT 2007


You are aware that the Mozilla project has a script that does exactly  
this, right? IIRC it's called unify.pl.

-Kevin Ballard

On Jun 24, 2007, at 6:57 AM, source_changes at macosforge.org wrote:

> Revision
> 26461
> Author
> pipping at macports.org
> Date
> 2007-06-24 06:57:23 -0700 (Sun, 24 Jun 2007)
> Log Message
>
> initial upload of <merge.rb>
>
> merge.rb is designed to merge two or more trees of single-arch  
> destdirs
> into a single destdir of universal binaries.
>
> build_coreutils.sh serves as a test, 'port destroot openssl  
> +universal' can
> be used as well (port install zlib +universal is required)
>
> see ./merge.rb --help for the usage
> Added Paths
>
> users/pipping/merge.rb
> Diff
>
> Added: users/pipping/merge.rb (0 => 26461)
>
> --- users/pipping/merge.rb	                        (rev 0)
> +++ users/pipping/merge.rb	2007-06-24 13:57:23 UTC (rev 26461)
> @@ -0,0 +1,221 @@
> +#!/usr/bin/env ruby -w
> +
> +# Copyright (c) 2007 Elias Pipping
> +#
> +# Permission is hereby granted, free of charge, to any person  
> obtaining a copy
> +# of this software and associated documentation files (the  
> "Software"), to deal
> +# in the Software without restriction, including without  
> limitation the rights
> +# to use, copy, modify, merge, publish, distribute, sublicense,  
> and/or sell
> +# copies of the Software, and to permit persons to whom the  
> Software is
> +# furnished to do so, subject to the following conditions:
> +#
> +# The above copyright notice and this permission notice shall be  
> included in
> +# all copies or substantial portions of the Software.
> +#
> +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,  
> EXPRESS OR
> +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF  
> MERCHANTABILITY,
> +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO  
> EVENT SHALL THE
> +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR  
> OTHER
> +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,  
> ARISING FROM,
> +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER  
> DEALINGS IN
> +# THE SOFTWARE.
> +
> +require 'fileutils'
> +require 'find'
> +require 'optparse'
> +require 'set'
> +
> +###
> +# we need GNU file with Apple's patches applied, available here:
> +# http://www.opensource.apple.com/darwinsource/Current/file-6.2/ 
> patches/
> +#
> +# Its output might span multiple lines, causing problems when  
> parsing, even
> +# with `file -b`, hence we'll assume we're not passed universal  
> binaries
> +# TODO: do a real check, maybe using `lipo -info` (fails on non- 
> Mach-O files)
> +FILE="/usr/bin/file"
> +
> +class MergeArguments < Hash
> +  def initialize(args)
> +    super()
> +
> +    # set up defaults
> +    self[:dry_run] = false
> +    self[:force]   = false
> +    self[:verbose] = false
> +
> +    self[:exclude] = Set.new << '.svn' << 'CVS'
> +    self[:root]    = Dir.pwd
> +
> +    opts = OptionParser.new do |opts|
> +      opts.banner = "Usage: #$0 [options] <arch> <arch> [<arch> ...]"
> +
> +      opts.on('-r', '--root DIRECTORY', 'specify root directory')  
> do |root|
> +        self[:root] = root || Dir.pwd
> +      end
> +
> +#     opts.on('-o', '--output DIRECTORY', 'specify output  
> directory') do |out|
> +#       self[:output] = File.expand_path(out) || File.join(self 
> [:root], 'out')
> +#     end
> +
> +      opts.on('-e', '--exclude NAMES', 'specify names of files/ 
> directories to exclude') do |exclude|
> +        self[:exclude] = Set.new
> +        exclude.split(" ").each do |item|
> +          self[:exclude] << item
> +        end
> +      end
> +
> +      opts.on('-d', '--dry-run', 'perform a dry run') do
> +        self[:dry_run] = true
> +      end
> +
> +      opts.on('-f', '--force', 'force writing, ignoring  
> collisions') do
> +        self[:force] = true
> +      end
> +
> +      opts.on('-v', '--verbose', 'enable verbose output') do
> +        self[:verbose] = true
> +      end
> +
> +      opts.on_tail('-h', '--help', 'display this help and exit') do
> +        puts opts
> +        exit
> +      end
> +    end
> +
> +    opts.parse!(args)
> +  end
> +end
> +
> +arguments = MergeArguments.new(ARGV)
> +
> +ARGS=ARGV.uniq
> +
> +def true_for_all? (filepath, args, &block)
> +  result=true
> +  ARGS.each {|arch|
> +    result=false unless yield(File.join(args[:root], arch),  
> filepath, arch)
> +  }
> +  return result
> +end
> +
> +def lipo (filepath,architectures,args)
> +  lipoargs = Array.new
> +  architectures.each {|arch|
> +    lipoargs << sprintf('-arch %s %s', arch, File.join(
> +      args[:root], arch, filepath
> +    ))
> +  }
> +  lipotarget=File.join(args[:root], 'out', filepath)
> +  lipocmd = sprintf(
> +    'lipo %s -create -o %s',
> +    lipoargs.join(' '),
> +    lipotarget
> +  )
> +  if !File.exist?(lipotarget) or args[:force]
> +    puts lipocmd if args[:verbose]
> +    system lipocmd if !args[:dry_run]
> +  end
> +end
> +
> +original_dir=Dir.pwd
> +processed=Set.new
> +
> +if File.directory?(File.expand_path(arguments[:root]))
> +  ARGS.each {|architecture|
> +    FileUtils.cd original_dir, :verbose => false
> +    if File.directory? File.join(
> +      File.expand_path(arguments[:root]), architecture
> +    )
> +      FileUtils.cd(
> +        File.join(arguments[:root], architecture),
> +        :verbose => arguments[:verbose]
> +      )
> +      Find.find('.') {|path|
> +        arguments[:exclude].each {|exclude_me|
> +          Find.prune if File.basename(path) == exclude_me
> +        }
> +        unless processed.include? path
> +          my_dir=File.dirname(File.join(arguments[:root], 'out',  
> path))
> +          # TODO: what if ppc/foo is a dir and i386/foo is a file  
> (symlink)? (1)
> +          unless File.exist? my_dir
> +            FileUtils.mkdir_p(
> +              my_dir,
> +              :verbose => arguments[:verbose],
> +              :noop => arguments[:dry_run]
> +            )
> +          end
> +          if true_for_all?(path, arguments) {|dir,filename,arch|
> +            File.exist?(File.join(dir, filename))
> +          }
> +            unless true_for_all?(path, arguments) {| 
> dir,filename,arch|
> +              File.directory?(File.join(dir, filename))
> +            }
> +
> +              if true_for_all?(path, arguments) {|dir,filename,arch|
> +                FileUtils.identical?(
> +                  File.join(dir, path),
> +                  File.join(arguments[:root], ARGS[0], path)
> +                )
> +              }
> +                copytarget=File.join(arguments[:root],'out',path)
> +                if !File.exist?(copytarget) or arguments[:force]
> +                  FileUtils.cp(
> +                    File.join(arguments[:root],ARGS[0],path),
> +                    copytarget,
> +                    :preserve => !arguments[:force],
> +                    :verbose => arguments[:verbose],
> +                    :noop => arguments [:dry_run]
> +                  )
> +                end
> +              else
> +                # TODO: make this not-blindly lipo but check  
> filetypes / archs
> +                # TODO: beware of symlinks!
> +                case File.basename path
> +                when /\.dylib(\.\d*)*/, /\.so(\.\d*)*/, /\.a$/
> +                  lipo(path,ARGS,arguments)
> +                when /\.h$/, /\.hpp$/
> +                  # TODO: handle header files
> +                when /\.pc$/
> +                  # TODO: handle pkgconfig files
> +                when /\.sh$/
> +                  # TODO: handle shell scripts
> +                else
> +                  case %x{#{FILE} -b "#{File.join(arguments 
> [:root],ARGS[0],path)}"}
> +                  when sprintf("Mach-O executable %s\n", ARGS[0])
> +                    if true_for_all?(path, arguments) {| 
> dir,filename,arch|
> +                      %x{#{FILE} -b "#{File.join(dir,path)}"} ==  
> sprintf("Mach-O executable %s\n", arch)
> +                    }
> +                      lipo(path,ARGS,arguments)
> +                    else
> +                      # one of the files is a mach-o file that  
> matches its
> +                      # desired architecture but one of the others  
> doesn't
> +                    end
> +                  # else
> +                    # TODO: deal with whatever else can differ
> +                  end
> +                end
> +              end
> +            else
> +              # TODO: at least one of the files is a directory (1)
> +            end
> +          else
> +            # TODO: a file is not present in all trees. what's wrong?
> +          end
> +          processed << path
> +        end
> +      }
> +    else
> +      raise sprintf(
> +        'architecture missing from root directory: %s',
> +        architecture
> +      )
> +    end
> +  }
> +else
> +  raise sprintf(
> +    'invalid root directory: %s',
> +    arguments[:root]
> +  )
> +end
> +
> +FileUtils.cd original_dir, :verbose => false
> Property changes on: users/pipping/merge.rb
> ___________________________________________________________________
> Name: svn:executable
>    + *
> _______________________________________________
> macports-changes mailing list
> macports-changes at lists.macosforge.org
> http://lists.macosforge.org/mailman/listinfo/macports-changes

-- 
Kevin Ballard
http://kevin.sb.org
eridius at macports.org
http://www.tildesoft.com


-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macports-dev/attachments/20070624/2cd32bfe/attachment.html


More information about the macports-dev mailing list