[26461] users/pipping/merge.rb

source_changes at macosforge.org source_changes at macosforge.org
Sun Jun 24 06:57:23 PDT 2007


Revision: 26461
          http://trac.macosforge.org/projects/macports/changeset/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

Added: users/pipping/merge.rb
===================================================================
--- 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
   + *

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macports-changes/attachments/20070624/8f2b599d/attachment.html


More information about the macports-changes mailing list