Ticket #17972: merge_universal-1.0.tcl

File merge_universal-1.0.tcl, 13.0 KB (added by MarcusCalhoun-Lopez (Marcus Calhoun-Lopez), 16 years ago)
Line 
1# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
2# merge_universal-1.0.tcl
3#
4# $Id$
5#
6# Copyright (c) 2008 The MacPorts Project,
7# All rights reserved.
8#
9# Redistribution and use in source and binary forms, with or without
10# modification, are permitted provided that the following conditions are
11# met:
12#
13# 1. Redistributions of source code must retain the above copyright
14#    notice, this list of conditions and the following disclaimer.
15# 2. Redistributions in binary form must reproduce the above copyright
16#    notice, this list of conditions and the following disclaimer in the
17#    documentation and/or other materials provided with the distribution.
18# 3. Neither the name of Apple Computer, Inc. nor the names of its
19#    contributors may be used to endorse or promote products derived from
20#    this software without specific prior written permission.
21#
22# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33#
34
35# User variables:
36#    merger_configure_env: associative array of configure.env variables
37#             merger_host: associative array of --host=... values
38#        merger_dont_diff: list of file names for which diff will not work
39
40variant universal {
41    eval configure.args-append      ${configure.universal_args}
42    eval configure.cflags-append    ${configure.universal_cflags}
43    eval configure.cxxflags-append  ${configure.universal_cxxflags}
44    eval configure.ldflags-append   ${configure.universal_ldflags}
45    eval configure.cppflags-append  ${configure.universal_cppflags}
46
47    foreach arch ${universal_archs} {
48        configure.cflags-delete    -arch ${arch}
49        configure.cxxflags-delete  -arch ${arch}
50        configure.ldflags-delete   -arch ${arch}
51    }
52
53    configure {
54        foreach arch ${universal_archs} {
55            ui_msg "universal: Running configure for architecture ${arch}"
56
57            copy ${worksrcpath} ${workpath}/${arch}
58
59            # Prefer -m to -arch
60            set archf "-arch ${arch}"
61            if { ${os.arch}=="i386" && ${arch}=="i386" } {
62                set archf -m32
63            } elseif { ${os.arch}=="i386" && ${arch}=="x86_64" } {
64                set archf -m64
65            } elseif { ${os.arch}=="powerpc" && ${arch}=="ppc" } {
66                set archf -m32
67            } elseif { ${os.arch}=="powerpc" && ${arch}=="ppc64" } {
68                set archf -m64
69            }
70            configure.cflags-append    ${archf}
71            configure.cxxflags-append  ${archf}
72
73            if { [info exists merger_configure_env(${arch})] } {
74                configure.env-append  $merger_configure_env(${arch})
75            }
76
77            # Don't set the --host unless we have to.
78            set host ""
79            if { ${os.arch}=="i386" && (${arch}=="ppc" || ${arch}=="ppc64") } {
80                if { [info exists merger_host(${arch})] } {
81                    set host  --host=$merger_host(${arch})
82                } else {
83                    set host --host=powerpc64-apple-darwin
84                }
85            } elseif { ${os.arch}=="powerpc" && (${arch}=="i386" || ${arch}=="x86_64") } {
86                if { [info exists merger_host(${arch})] } {
87                    set host  --host=$merger_host(${arch})
88                } else {
89                    set host --host=core2-apple-darwin
90                }
91            }
92            configure.args-append  ${host}
93
94            set worksrcpathSave  ${worksrcpath}
95            set worksrcpath  ${workpath}/${arch}
96
97            configure_main
98
99            # Undo changes to the configure related variables
100            set worksrcpath  ${worksrcpathSave}
101            configure.args-delete  ${host}
102            if { [info exists merger_configure_env(${arch})] } {
103                configure.env-delete  $merger_configure_env(${arch})
104            }
105            configure.cxxflags-delete ${archf}
106            configure.cflags-delete ${archf}
107        }
108    }
109
110    build {
111        foreach arch ${universal_archs} {
112            ui_msg "universal: Running build for architecture ${arch}"
113            build.dir  ${workpath}/${arch}
114                        build_main
115                }
116    }
117
118        destroot {
119        foreach arch ${universal_archs} {
120            ui_msg "universal: Running build for architecture ${arch}"
121            copy ${destroot} ${workpath}/destroot-${arch}
122            destroot.dir  ${workpath}/${arch}
123            destroot.destdir  DESTDIR=${workpath}/destroot-${arch}
124            destroot_main
125        }
126        delete ${destroot}
127
128        # Merge ${base1}/${prefixDir} and ${base2}/${prefixDir} into dir ${base}/${prefixDir}
129        #        arch1, arch2: names to prepend to files if a diff merge of two files is forbiddend by merger_dont_diff
130        #    merger_dont_diff: list of files for which /usr/bin/diff ${diffFormat} will not merge correctly
131        #          diffFormat: format used by diff to merge two text files
132        proc merge2Dir {base1 base2 base prefixDir arch1 arch2 merger_dont_diff diffFormat} {
133            set dir1  ${base1}/${prefixDir}
134            set dir2  ${base2}/${prefixDir}
135            set dir   ${base}/${prefixDir}
136
137            xinstall -d -m 0755 ${dir}
138
139            foreach fl [glob -directory ${dir2} -tails -nocomplain *] {
140                if { ![file exists ${dir1}/${fl}] } {
141                    # File only exists in ${dir1}
142                    ui_debug "universal: merge: ${prefixDir}/${fl} only exists in ${base2}"
143                    copy ${dir2}/${fl} ${dir}
144                }
145            }
146            foreach fl [glob -directory ${dir1} -tails -nocomplain *] {
147                if { ![file exists ${dir2}/${fl}] } {
148                    # File only exists in ${dir2}
149                    ui_debug "universal: merge: ${prefixDir}/${fl} only exists in ${base1}"
150                    copy ${dir1}/${fl} ${dir}
151                } else {
152                    # File exists in ${dir1} and ${dir2}
153                    ui_debug "universal: merge: merging ${prefixDir}/${fl} from ${base1} and ${base2}"
154
155                    # Ensure files are of same type
156                    if { [file type ${dir1}/${fl}]!=[file type ${dir2}/${fl}] } {
157                        error "${dir1}/${fl} and ${dir2}/${fl} are of different types"
158                    }
159
160                    if { [file isdirectory ${dir1}/${fl}] } {
161                        # Files are directories, so recursively call function
162                        merge2Dir ${base1} ${base2} ${base} ${prefixDir}/${fl} ${arch1} ${arch2} ${merger_dont_diff} ${diffFormat}
163                    } elseif { [file type ${dir1}/${fl}]=="link" } {
164                        # Files are links
165                        ui_debug "universal: merge: ${prefixDir}/${fl} is a link"
166
167                        # Ensure links don't point to different things
168                        if { [file readlink ${dir1}/${fl}]==[file readlink ${dir2}/${fl}] } {
169                            copy ${dir1}/${fl} ${dir}
170                        } else {
171                            error "${dir1}/${fl} and ${dir2}/${fl} point to different targets (can't merge them)"
172                        }
173                    } else {
174                        # Files are neither directories nor links
175
176                        if { ! [catch {system "/usr/bin/cmp ${dir1}/${fl} ${dir2}/${fl} && /bin/cp -v ${dir1}/${fl} ${dir}"}] } {
177                            # Files are byte by byte the same
178                            ui_debug "universal: merge: ${prefixDir}${fl} is identical in ${base1} and ${base2}"
179                        } else {
180                            # Actually try to merge the files
181                            # First try lipo
182                            if { ! [catch {system "/usr/bin/lipo -create ${dir1}/${fl} ${dir2}/${fl} -output ${dir}/${fl}"}] } {
183                                # lipo worked
184                                ui_debug "universal: merge: lipo created ${prefixDir}/${fl}"
185                            } else {
186                                # lipo has failed, so assume they are text files to be merged
187                                set dontdiff no
188                                foreach dont ${merger_dont_diff} {
189                                    if { ${dont}==${prefixDir}/${fl} } {
190                                        set dontdiff yes
191                                    }
192                                }
193                                if { ${dontdiff}==yes } {
194                                    # user has specified that diff does not work
195                                    # attempt to give each file a unique name and create a new file which includes one of the origional depending on the arch
196
197                                    set fh [open ${dir}/${arch1}-${fl} w 0644]
198                                    puts ${fh} "#include \"${arch1}-${fl}\""
199                                    close ${fh}
200
201                                    set fh [open ${dir}/${arch2}-${fl} w 0644]
202                                    puts ${fh} "#include \"${arch2}-${fl}\""
203                                    close ${fh}
204
205                                    ui_debug "universal: merge: created ${prefixDir}/${fl} to include ${prefixDir}/${arch1}-${fl} ${prefixDir}/${arch1}-${fl}"
206
207                                    system "/usr/bin/diff -d ${diffFormat} ${dir}/${arch1}-${fl} ${dir}/${arch2}-${fl} > ${dir}/${fl}; test \$? -le 1"
208
209                                    copy -force ${dir1}/${fl} ${dir}/${arch1}-${fl}
210                                    copy -force ${dir2}/${fl} ${dir}/${arch2}-${fl}
211                                } elseif { ! [catch {system "(/usr/bin/diff -dw ${diffFormat} ${dir1}/${fl} ${dir2}/${fl} > ${dir}/${fl}; test \$? -le 1) || rm ${dir}/${fl}"} ] } {
212                                    # diff worked
213                                    ui_debug "universal: merge: used diff to create ${prefixDir}/${fl}"
214                                } else {
215                                    # nothing has worked so far.
216                                    switch -glob ${fl} {
217                                        *.jar {
218                                            # jar files can be different becasue of timestamp
219                                            ui_debug "universal: merge: ${prefixDir}/${fl} is different in ${base1} and ${base2}; assume timestamp difference"
220                                            copy ${dir1}/${fl} ${dir}
221                                        }
222                                        default {
223                                            error "Can not create ${prefixDir}/${fl} from ${base1} and ${base2}"
224                                        }
225                                    }
226                                }
227                            }
228                        }
229                    }
230                }
231            }
232        }
233
234        # /usr/bin/diff can merge two C/C++ files
235        # See http://www.gnu.org/software/diffutils/manual/html_mono/diff.html#If-then-else
236        # See http://www.gnu.org/software/diffutils/manual/html_mono/diff.html#Detailed%20If-then-else
237        set diffFormatProc {--old-group-format='#if (defined(__ppc__) || defined(__ppc64__))
238 %<#endif /* __ppc__ || __ppc64__ */
239' \
240--new-group-format='#if defined (__i386__) || defined(__x86_64__)
241%>#endif /* __i386__ || __x86_64__ */
242' \
243--unchanged-group-format='%=' \
244--changed-group-format='#if (defined(__ppc__) || defined(__ppc64__))
245%<#else /* __ppc__ || __ppc64__ */
246%>#endif /* __ppc__ || __ppc64__ */
247'}
248
249        set diffFormatM "-D __LP64__"
250
251        if { ![info exists merger_dont_diff] } {
252            set merger_dont_diff {}
253        }
254
255        merge2Dir ${workpath}/destroot-ppc ${workpath}/destroot-ppc64 ${workpath}/destroot-powerpc "" ppc ppc64 ${merger_dont_diff} ${diffFormatM}
256        merge2Dir ${workpath}/destroot-i386 ${workpath}/destroot-x86_64 ${workpath}/destroot-intel "" i386 x86_64 ${merger_dont_diff} ${diffFormatM}
257        merge2Dir ${workpath}/destroot-powerpc ${workpath}/destroot-intel ${workpath}/destroot "" powerpc x86 ${merger_dont_diff} ${diffFormatProc}
258    }
259
260    test {
261        foreach arch ${universal_archs} {
262            # Rosetta does not translate G5 instructions
263            # PowerPC systems can't translate Intel instructions
264            if { (${os.arch}=="i386" && ${arch}!="ppc64") || (${os.arch}=="powerpc" && ${arch}!="i386" && ${arch}!="x86_64") } {
265                ui_msg "universal: Running test for architecture ${arch}"
266                test.dir  ${workpath}/${arch}
267                test_main
268            }
269        }
270    }
271}