source: trunk/dports/_resources/port1.0/group/muniversal-1.0.tcl @ 104547

Last change on this file since 104547 was 104547, checked in by michaelld@…, 6 years ago

muniversal PortGroup: add merger-post-destroot hook to allow tweaking of destroot before merger

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 35.9 KB
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# $Id: muniversal-1.0.tcl 104547 2013-03-27 15:47:49Z michaelld@macports.org $
3#
4# Copyright (c) 2009-2013 The MacPorts Project,
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions are
9# met:
10#
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16# 3. Neither the name of Apple Computer, Inc. nor the names of its
17#    contributors may be used to endorse or promote products derived from
18#    this software without specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31#
32
33# User variables:
34#         merger_configure_env: associative array of configure.env variables
35#             merger_build_env: associative array of build.env variables
36#                  merger_host: associative array of host values
37#        merger_configure_args: associative array of configure.args
38#            merger_build_args: associative array of build.args
39#    merger_configure_compiler: associative array of configure.compiler
40#    merger_configure_cppflags: associative array of configure.cppflags
41#      merger_configure_cflags: associative array of configure.cflags
42#    merger_configure_cxxflags: associative array of configure.cxxflags
43#   merger_configure_objcflags: associative array of configure.objcflags
44#     merger_configure_ldflags: associative array of configure.ldflags
45#             merger_arch_flag: if no, -arch xxx will not be appended configure.???flags
46#         merger_arch_compiler: if no, -arch xxx will not be appended to compilers
47#          merger_destroot_env: associative array of destroot.env variables
48#             merger_dont_diff: list of file names for which diff will not work
49#     merger_must_run_binaries: if yes, build platform must be able to run binaries for supported architectures
50#            merger_no_3_archs: if yes, merger will not work correctly if there are three supported architectures
51
52options universal_archs_supported merger_must_run_binaries merger_no_3_archs merger_arch_flag merger_arch_compiler
53default universal_archs_supported {${universal_archs}}
54default merger_must_run_binaries {no}
55default merger_no_3_archs {no}
56default merger_arch_flag {yes}
57default merger_arch_compiler {no}
58
59proc muniversal_arch_flag_supported {args} {
60    global configure.compiler
61    return [regexp {^gcc-4|llvm|apple|clang} ${configure.compiler}]
62}
63
64proc muniversal_get_arch_flag {arch {fortran ""}} {
65    global os.arch
66    # Prefer -arch to -m
67    if {[muniversal_arch_flag_supported] && ${fortran}==""} {
68        set archf "-arch ${arch}"
69    } else {
70        if { ${os.arch}=="i386" && ${arch}=="i386" } {
71            set archf -m32
72        } elseif { ${os.arch}=="i386" && ${arch}=="x86_64" } {
73            set archf -m64
74        } elseif { ${os.arch}=="powerpc" && ${arch}=="ppc" } {
75            set archf -m32
76        } elseif { ${os.arch}=="powerpc" && ${arch}=="ppc64" } {
77            set archf -m64
78        } else {
79            if { ${fortran}=="" } {
80                return -code error "selected compiler can't build for ${arch}"
81            } else {
82                return ""
83            }
84        }
85    }
86    return ${archf}
87}
88
89# set up the merger-post-destroot hook
90
91proc merger_target_provides {ditem args} {
92    global targets
93    # register just the procedure, no pre-/post-
94    # User-code exceptions are caught and returned as a result of the target.
95    # Thus if the user code breaks, dependent targets will not execute.
96    foreach target $args {
97        set origproc [ditem_key $ditem procedure]
98        set ident [ditem_key $ditem name]
99        proc merger-post-$target {args} "
100            variable proc_index
101            set proc_index \[llength \[ditem_key $ditem post\]\]
102            ditem_append $ditem merger-post proc-merger-post-${ident}-${target}-\${proc_index}
103            proc proc-merger-post-${ident}-${target}-\${proc_index} {name} \"
104                if {\\\[catch userproc-merger-post-${ident}-${target}-\${proc_index} result\\\]} {
105                    return -code error \\\$result
106                } else {
107                    return 0
108                }
109            \"
110            makeuserproc userproc-merger-post-${ident}-${target}-\${proc_index} \$args
111        "
112    }
113}
114
115merger_target_provides ${org.macports.destroot} destroot
116
117variant universal {
118    global universal_archs_to_use
119
120    foreach arch ${universal_archs} {
121        configure.universal_cflags-delete    -arch ${arch}
122        configure.universal_cxxflags-delete  -arch ${arch}
123        configure.universal_ldflags-delete   -arch ${arch}
124    }
125
126    eval configure.args-append      ${configure.universal_args}
127    eval configure.cflags-append    ${configure.universal_cflags}
128    eval configure.cxxflags-append  ${configure.universal_cxxflags}
129    eval configure.objcflags-append ${configure.universal_cflags}
130    eval configure.ldflags-append   ${configure.universal_ldflags}
131    eval configure.cppflags-append  ${configure.universal_cppflags}
132
133    # user has specified that build platform must be able to run binaries for supported architectures
134    if { ${merger_must_run_binaries}=="yes" } {
135        if { ${os.arch}=="i386" } {
136            set universal_archs_supported [ldelete ${universal_archs_supported} "ppc64"]
137            if {${os.major} >= 9 && [sysctl hw.cpu64bit_capable] == 0} {
138                set universal_archs_supported [ldelete ${universal_archs_supported} "x86_64"]
139            }
140        } else {
141            set universal_archs_supported [ldelete ${universal_archs_supported} "i386"]
142            set universal_archs_supported [ldelete ${universal_archs_supported} "x86_64"]
143            if {${os.major} >= 9 && [sysctl hw.cpu64bit_capable] == 0} {
144                set universal_archs_supported [ldelete ${universal_archs_supported} "ppc64"]
145            }
146        }
147    }
148
149    # set universal_archs_to_use as the intersection of universal_archs and universal_archs_supported
150    set universal_archs_to_use {}
151    foreach arch ${universal_archs} {
152        set arch_ok no
153        foreach archt ${universal_archs_supported} {
154            if { ${arch}==${archt} } {
155                set arch_ok yes
156            }
157        }
158        if { ${arch_ok}=="yes" } {
159            lappend universal_archs_to_use ${arch}
160        }
161    }
162
163    # if merger_no_3_archs is yes, prune universal_archs_to_use until it only has two elements
164    if { ${merger_no_3_archs}=="yes" } {
165        if { [llength ${universal_archs_to_use}] == 3 } {
166            # first try to remove cross-compiled 64-bit arch
167            if { ${os.arch}=="i386" } {
168                set universal_archs_to_use [ldelete ${universal_archs_to_use} "ppc64"]
169            } else {
170                set universal_archs_to_use [ldelete ${universal_archs_to_use} "x86_64"]
171            }
172        }
173        if { [llength ${universal_archs_to_use}] == 3 } {
174            # next try to remove cross-compiled 32-bit arch
175            if { ${os.arch}=="i386" } {
176                set universal_archs_to_use [ldelete ${universal_archs_to_use} "ppc"]
177            } else {
178                set universal_archs_to_use [ldelete ${universal_archs_to_use} "i386"]
179            }
180        }
181        if { [llength ${universal_archs_to_use}] == 3 } {
182            # at least one arch should have been removed from universal_archs_to_use
183            error "Should Not Happen"
184        }
185    }
186
187    configure {
188        # Fix inability to find nm when cross-compiling (#22224, #23431, #23687, #24477, et al)
189        configure.env-append    NM=/usr/bin/nm
190
191        foreach arch ${universal_archs_to_use} {
192            ui_info "$UI_PREFIX [format [msgcat::mc "Configuring %1\$s for architecture %2\$s"] $name ${arch}]"
193
194            copy ${worksrcpath} ${worksrcpath}-${arch}
195
196            set archf [muniversal_get_arch_flag ${arch}]
197            set archff [muniversal_get_arch_flag ${arch} "fortran"]
198
199            if { ${merger_arch_flag} != "no" } {
200                configure.cflags-append    ${archf}
201                configure.cxxflags-append  ${archf}
202                configure.objcflags-append ${archf}
203                configure.fflags-append    ${archff}
204                configure.fcflags-append   ${archff}
205                configure.f90flags-append  ${archff}
206                configure.ldflags-append   ${archf}
207            }
208
209            if { [info exists merger_configure_env(${arch})] } {
210                configure.env-append  $merger_configure_env(${arch})
211            }
212            if { [info exists merger_configure_cppflags(${arch})] } {
213                configure.cppflags-append  $merger_configure_cppflags(${arch})
214            }
215            if { [info exists merger_configure_cflags(${arch})] } {
216                configure.cflags-append  $merger_configure_cflags(${arch})
217            }
218            if { [info exists merger_configure_cxxflags(${arch})] } {
219                configure.cxxflags-append  $merger_configure_cxxflags(${arch})
220            }
221            if { [info exists merger_configure_objcflags(${arch})] } {
222                configure.objcflags-append  $merger_configure_objcflags(${arch})
223            }
224            if { [info exists merger_configure_ldflags(${arch})] } {
225                configure.ldflags-append  $merger_configure_ldflags(${arch})
226            }
227
228            # Don't set the --host unless we have to.
229            set host ""
230            if { [info exists merger_host($arch)] } {
231                if { $merger_host($arch) != "" } {
232                    set host  --host=$merger_host($arch)
233                }
234            } elseif {[file tail ${configure.cmd}] != "cmake"} {
235                # check if building for a word length we can't run
236                set bits_differ 0
237                if {(${arch}=="x86_64" || ${arch}=="ppc64") &&
238                    (${os.major} < 9 || [sysctl hw.cpu64bit_capable] == 0)} {
239                    set bits_differ 1
240                }
241                # check if building for a completely different arch
242                if {$bits_differ || (${os.arch}=="i386" && (${arch}=="ppc" || ${arch}=="ppc64"))
243                        || (${os.arch}=="powerpc" && (${arch}=="i386" || ${arch}=="x86_64"))
244                        || $macosx_deployment_target != $macosx_version} {
245                    if {$macosx_deployment_target == $macosx_version} {
246                        set hostversion ${os.version}
247                    } else {
248                        set hostversion [expr [lindex [split $macosx_deployment_target .] 1] + 4]
249                    }
250                    switch -- ${arch} {
251                        x86_64  {set host "--host=x86_64-apple-${os.platform}${hostversion}"}
252                        i386    {set host "--host=i686-apple-${os.platform}${hostversion}"}
253                        ppc     {set host "--host=powerpc-apple-${os.platform}${hostversion}"}
254                        ppc64   {set host "--host=powerpc64-apple-${os.platform}${hostversion}"}
255                    }
256                }
257            }
258            if {$host != ""} {
259                configure.args-append  ${host}
260            }
261
262            if { [info exists merger_configure_args(${arch})] } {
263                configure.args-append  $merger_configure_args(${arch})
264            }
265
266            set configure_compiler_save ${configure.compiler}
267            set configure_cc_save       ${configure.cc}
268            set configure_cxx_save      ${configure.cxx}
269            set configure_objc_save     ${configure.objc}
270            set configure_fc_save       ${configure.fc}
271            set configure_f77_save      ${configure.f77}
272            set configure_f90_save      ${configure.f90}
273
274            if { [info exists merger_configure_compiler($arch)] } {
275                configure.compiler  $merger_configure_compiler($arch)
276                configure.cc        [portconfigure::configure_get_compiler cc]
277                configure.cxx       [portconfigure::configure_get_compiler cxx]
278                configure.objc      [portconfigure::configure_get_compiler objc]
279                configure.f77       [portconfigure::configure_get_compiler f77]
280                configure.f90       [portconfigure::configure_get_compiler f90]
281                configure.fc        [portconfigure::configure_get_compiler fc]
282            }
283
284            if { ${merger_arch_compiler} != "no" } {
285                configure.cc   ${configure.cc}   ${archf}
286                configure.cxx  ${configure.cxx}  ${archf}
287                configure.objc ${configure.objc} ${archf}
288                if { ${configure.fc}  != "" } { configure.fc   ${configure.fc}  ${archff} }
289                if { ${configure.f77} != "" } { configure.f77  ${configure.f77} ${archff} }
290                if { ${configure.f90} != "" } { configure.f90  ${configure.f90} ${archff} }
291            }
292
293            set configure_dir_save  ${configure.dir}
294            if { [string match "${worksrcpath}/*" ${configure.dir}] } {
295                # The configure directory is inside the source directory, so put in the new source directory name.
296                eval configure.dir  [string map "${worksrcpath} ${worksrcpath}-${arch}" ${configure.dir}]
297            } else {
298                # The configure directory is outside the source directory, so give it a new name by appending ${arch}.
299                configure.dir  ${configure.dir}-${arch}
300                if { ![file exists ${configure.dir}] } {
301                    file mkdir ${configure.dir}
302                }
303            }
304
305            set autoreconf_dir_save  ${autoreconf.dir}
306            if { [string match "${worksrcpath}/*" ${autoreconf.dir}] } {
307                # The autoreconf directory is inside the source directory, so put in the new source directory name.
308                eval autoreconf.dir  [string map "${worksrcpath} ${worksrcpath}-${arch}" ${autoreconf.dir}]
309            } else {
310                # The autoreconf directory is outside the source directory, so give it a new name by appending ${arch}.
311                autoreconf.dir  ${autoreconf.dir}-${arch}
312                if { ![file exists ${autoreconf.dir}] } {
313                    file mkdir ${autoreconf.dir}
314                }
315            }
316
317            portconfigure::configure_main
318
319            # Undo changes to the configure related variables
320            eval autoreconf.dir ${autoreconf_dir_save}
321            eval configure.dir  ${configure_dir_save}
322            eval configure.compiler ${configure_compiler_save}
323            eval configure.f90  ${configure_f90_save}
324            eval configure.f77  ${configure_f77_save}
325            eval configure.fc   ${configure_fc_save}
326            eval configure.cc   ${configure_cc_save}
327            eval configure.cxx  ${configure_cxx_save}
328            eval configure.objc ${configure_objc_save}
329            if { [info exists merger_configure_args(${arch})] } {
330                configure.args-delete  $merger_configure_args(${arch})
331            }
332            configure.args-delete  ${host}
333            if { [info exists merger_configure_ldflags(${arch})] } {
334                configure.ldflags-delete  $merger_configure_ldflags(${arch})
335            }
336            if { [info exists merger_configure_cxxflags(${arch})] } {
337                configure.cxxflags-delete  $merger_configure_cxxflags(${arch})
338            }
339            if { [info exists merger_configure_objcflags(${arch})] } {
340                configure.objcflags-delete  $merger_configure_objcflags(${arch})
341            }
342            if { [info exists merger_configure_cflags(${arch})] } {
343                configure.cflags-delete  $merger_configure_cflags(${arch})
344            }
345            if { [info exists merger_configure_cppflags(${arch})] } {
346                configure.cppflags-delete  $merger_configure_cppflags(${arch})
347            }
348            if { [info exists merger_configure_env(${arch})] } {
349                configure.env-delete  $merger_configure_env(${arch})
350            }
351            if { ${merger_arch_flag} != "no" } {
352                configure.ldflags-delete   ${archf}
353                configure.f90flags-delete  ${archff}
354                configure.fcflags-delete   ${archff}
355                configure.fflags-delete    ${archff}
356                configure.objcflags-delete ${archf}
357                configure.cxxflags-delete  ${archf}
358                configure.cflags-delete    ${archf}
359            }
360        }
361    }
362
363    build {
364        foreach arch ${universal_archs_to_use} {
365            ui_info "$UI_PREFIX [format [msgcat::mc "Building %1\$s for architecture %2\$s"] $name ${arch}]"
366
367            if { [info exists merger_build_env(${arch})] } {
368                build.env-append  $merger_build_env(${arch})
369            }
370            if { [info exists merger_build_args(${arch})] } {
371                build.args-append  $merger_build_args(${arch})
372            }
373            set build_dir_save  ${build.dir}
374            if { [string match "${worksrcpath}/*" ${build.dir}] } {
375                # The build directory is inside the source directory, so put in the new source directory name.
376                eval build.dir  [string map "${worksrcpath} ${worksrcpath}-${arch}" ${build.dir}]
377            } else {
378                # The build directory is outside the source directory, so give it a new name by appending ${arch}.
379                build.dir  ${build.dir}-${arch}
380                if { ![file exists ${build.dir}] } {
381                    file mkdir ${build.dir}
382                }
383            }
384
385            portbuild::build_main
386
387            eval build.dir  ${build_dir_save}
388            if { [info exists merger_build_args(${arch})] } {
389                build.args-delete $merger_build_args(${arch})
390            }
391            if { [info exists merger_build_env(${arch})] } {
392                build.env-delete  $merger_build_env(${arch})
393            }
394        }
395    }
396
397    destroot {
398        foreach arch ${universal_archs_to_use} {
399            ui_info "$UI_PREFIX [format [msgcat::mc "Staging %1\$s into destroot for architecture %2\$s"] $name ${arch}]"
400            copy ${destroot} ${workpath}/destroot-${arch}
401            set destdirSave ${destroot.destdir}
402            eval destroot.destdir  [string map "${destroot} ${workpath}/destroot-${arch}" ${destroot.destdir}]
403
404            if { [info exists merger_destroot_env(${arch})] } {
405                destroot.env-append  $merger_destroot_env(${arch})
406            }
407            set destroot_dir_save ${destroot.dir}
408            if { [string match "${worksrcpath}/*" ${destroot.dir}] } {
409                # The destroot directory is inside the source directory, so put in the new source directory name.
410                eval destroot.dir  [string map "${worksrcpath} ${worksrcpath}-${arch}" ${destroot.dir}]
411            } else {
412                # The destroot directory is outside the source directory, so give it a new name by appending ${arch}.
413                destroot.dir  ${destroot.dir}-${arch}
414                if { ![file exists ${destroot.dir}] } {
415                    file mkdir ${destroot.dir}
416                }
417            }
418
419            portdestroot::destroot_main
420
421            destroot.dir  ${destroot_dir_save}
422            if { [info exists merger_destroot_env(${arch})] } {
423                destroot.env-delete  $merger_destroot_env(${arch})
424            }
425            eval destroot.destdir ${destdirSave}
426        }
427        delete ${destroot}
428
429        # execute merger-post-destroot, if it exists
430
431        set ditem ${org.macports.destroot}
432        set procedure [ditem_key $ditem merger-post]
433        if {$procedure != ""} {
434            set targetname [ditem_key $ditem name]
435            ui_debug "Executing org.macports.merger-post-destroot"
436            set result [catch { $procedure $targetname } errstr]
437            # Save variables in order to re-throw the same error code.
438            set errcode $::errorCode
439            set errinfo $::errorInfo
440            if {$result != 0} {
441                set portname $subport
442                ui_error "$targetname for port $portname returned: $errstr"
443                ui_debug "Error code: $errcode"
444                ui_debug "Backtrace: $errinfo"
445                return $result
446            }
447        }
448
449        # Merge ${base1}/${prefixDir} and ${base2}/${prefixDir} into dir ${base}/${prefixDir}
450        #        arch1, arch2: names to prepend to files if a diff merge of two files is forbidden by merger_dont_diff
451        #    merger_dont_diff: list of files for which /usr/bin/diff ${diffFormat} will not merge correctly
452        #          diffFormat: format used by diff to merge two text files
453        proc merge2Dir {base1 base2 base prefixDir arch1 arch2 merger_dont_diff diffFormat} {
454            set dir1  ${base1}/${prefixDir}
455            set dir2  ${base2}/${prefixDir}
456            set dir   ${base}/${prefixDir}
457
458            xinstall -d -m 0755 ${dir}
459
460            foreach fl [glob -directory ${dir2} -tails -nocomplain *] {
461                if { ![muniversal_file_or_symlink_exists ${dir1}/${fl}] } {
462                    # File only exists in ${dir1}
463                    ui_debug "universal: merge: ${prefixDir}/${fl} only exists in ${base2}"
464                    copy ${dir2}/${fl} ${dir}
465                }
466            }
467            foreach fl [glob -directory ${dir1} -tails -nocomplain *] {
468                if { ![muniversal_file_or_symlink_exists ${dir2}/${fl}] } {
469                    # File only exists in ${dir2}
470                    ui_debug "universal: merge: ${prefixDir}/${fl} only exists in ${base1}"
471                    copy ${dir1}/${fl} ${dir}
472                } else {
473                    # File exists in ${dir1} and ${dir2}
474                    ui_debug "universal: merge: merging ${prefixDir}/${fl} from ${base1} and ${base2}"
475
476                    # Ensure files are of same type
477                    if { [file type ${dir1}/${fl}]!=[file type ${dir2}/${fl}] } {
478                        error "${dir1}/${fl} and ${dir2}/${fl} are of different types"
479                    }
480
481                    if { [file type ${dir1}/${fl}]=="link" } {
482                        # Files are links
483                        ui_debug "universal: merge: ${prefixDir}/${fl} is a link"
484
485                        # Ensure links don't point to different things
486                        if { [file readlink ${dir1}/${fl}]==[file readlink ${dir2}/${fl}] } {
487                            copy ${dir1}/${fl} ${dir}
488                        } else {
489                            error "${dir1}/${fl} and ${dir2}/${fl} point to different targets (can't merge them)"
490                        }
491                    } elseif { [file isdirectory ${dir1}/${fl}] } {
492                        # Files are directories (but not links), so recursively call function
493                        merge2Dir ${base1} ${base2} ${base} ${prefixDir}/${fl} ${arch1} ${arch2} ${merger_dont_diff} ${diffFormat}
494                    } else {
495                        # Files are neither directories nor links
496                        if { ! [catch {system "/usr/bin/cmp \"${dir1}/${fl}\" \"${dir2}/${fl}\" && /bin/cp -v \"${dir1}/${fl}\" \"${dir}\""}] } {
497                            # Files are byte by byte the same
498                            ui_debug "universal: merge: ${prefixDir}/${fl} is identical in ${base1} and ${base2}"
499                        } else {
500                            # Actually try to merge the files
501                            # First try lipo, then libtool
502                            if { ! [catch {system "/usr/bin/lipo -create \"${dir1}/${fl}\" \"${dir2}/${fl}\" -output \"${dir}/${fl}\""}] } {
503                                # lipo worked
504                                ui_debug "universal: merge: lipo created ${prefixDir}/${fl}"
505                            } elseif { ! [catch {system "/usr/bin/libtool \"${dir1}/${fl}\" \"${dir2}/${fl}\" -o \"${dir}/${fl}\""}] } {
506                                # libtool worked
507                                ui_debug "universal: merge: libtool created ${prefixDir}/${fl}"
508                            } else {
509                                # lipo and libtool have failed, so assume they are text files to be merged
510                                set dontdiff no
511                                foreach dont ${merger_dont_diff} {
512                                    if { ${dont}=="${prefixDir}/${fl}" } {
513                                        set dontdiff yes
514                                    }
515                                }
516                                if { ${dontdiff}==yes } {
517                                    # user has specified that diff does not work
518                                    # attempt to give each file a unique name and create a new file which includes one of the original depending on the arch
519
520                                    set fh [open ${dir}/${arch1}-${fl} w 0644]
521                                    puts ${fh} "#include \"${arch1}-${fl}\""
522                                    close ${fh}
523
524                                    set fh [open ${dir}/${arch2}-${fl} w 0644]
525                                    puts ${fh} "#include \"${arch2}-${fl}\""
526                                    close ${fh}
527
528                                    ui_debug "universal: merge: created ${prefixDir}/${fl} to include ${prefixDir}/${arch1}-${fl} ${prefixDir}/${arch1}-${fl}"
529
530                                    system "/usr/bin/diff -d ${diffFormat} \"${dir}/${arch1}-${fl}\" \"${dir}/${arch2}-${fl}\" > \"${dir}/${fl}\"; test \$? -le 1"
531
532                                    copy -force ${dir1}/${fl} ${dir}/${arch1}-${fl}
533                                    copy -force ${dir2}/${fl} ${dir}/${arch2}-${fl}
534                                } else {
535                                    set known_file "no"
536
537                                    # Text file on which diff will not give correct results.
538                                    switch -glob ${fl} {
539                                        *.mod {
540                                            # .mod files from Fortran modules.
541                                            # Create a sepcial module directory for each architecture.
542                                            # To find these modules, GFortran might require -M or -J.
543                                            set known_file "yes"
544                                            file mkdir ${dir}/mods32
545                                            file mkdir ${dir}/mods64
546                                            if { ${arch1}=="i386" || ${arch1}=="ppc" } {
547                                                copy ${dir1}/${fl} ${dir}/mods32
548                                                copy ${dir2}/${fl} ${dir}/mods64
549                                            } else {
550                                                copy ${dir2}/${fl} ${dir}/mods32
551                                                copy ${dir1}/${fl} ${dir}/mods64
552                                            }
553                                        }
554                                        *.la -
555                                        *.pc -
556                                        *-config {
557                                            return -code error "${prefixDir}/${fl} differs in ${base1} and ${base2} and cannot be merged"
558                                        }
559                                    }
560
561                                    if { ${known_file}=="no" } {
562                                        if { ! [catch {system "/usr/bin/diff -dw ${diffFormat} \"${dir1}/${fl}\" \"${dir2}/${fl}\" > \"${dir}/${fl}\"; test \$? -le 1"} ] } {
563                                            # diff worked
564                                            ui_debug "universal: merge: used diff to create ${prefixDir}/${fl}"
565                                        } else {
566                                            # File created by diff is invalid
567                                            delete ${dir}/${fl}
568
569                                            # nothing has worked so far.
570                                            switch -glob ${fl} {
571                                                *.jar {
572                                                    # jar files can be different because of timestamp
573                                                    ui_debug "universal: merge: ${prefixDir}/${fl} differs in ${base1} and ${base2}; assume timestamp difference"
574                                                    copy ${dir1}/${fl} ${dir}
575                                                }
576                                                *.elc {
577                                                    # elc files can be different because they record when and where they were built.
578                                                    ui_debug "universal: merge: ${prefixDir}/${fl} differs in ${base1} and ${base2}; assume trivial difference"
579                                                    copy ${dir1}/${fl} ${dir}
580                                                }
581                                                *.gz -
582                                                *.bz2 {
583                                                    # compressed files can differ due to entropy
584                                                    switch -glob ${fl} {
585                                                        *.gz {
586                                                            set cat /usr/bin/gzcat
587                                                        }
588                                                        *.bz2 {
589                                                            set cat /usr/bin/bzcat
590                                                        }
591                                                    }
592                                                    set tempdir [mkdtemp "/tmp/muniversal.XXXXXXXX"]
593                                                    set tempfile1 "${tempdir}/${arch1}-[file rootname ${fl}]"
594                                                    set tempfile2 "${tempdir}/${arch2}-[file rootname ${fl}]"
595                                                    system "${cat} \"${dir1}/${fl}\" > \"${tempfile1}\""
596                                                    system "${cat} \"${dir2}/${fl}\" > \"${tempfile2}\""
597                                                    set identical "no"
598                                                    if { ! [catch {system "/usr/bin/cmp -s \"${tempfile1}\" \"${tempfile2}\""}] } {
599                                                        # files are identical
600                                                        ui_debug "universal: merge: ${prefixDir}/${fl} differs in ${base1} and ${base2} but the contents are the same"
601                                                        set identical "yes"
602                                                        copy ${dir1}/${fl} ${dir}
603                                                    }
604                                                    if { ${identical}=="no" } {
605                                                        switch -glob ${fl} {
606                                                            *.el.gz {
607                                                                # Emacs lisp files should be same across architectures
608                                                                # the emacs package (and perhaps others) records the date of automatically generated el files
609                                                                ui_debug "universal: merge: ${prefixDir}/${fl} differs in ${base1} and ${base2}; assume trivial difference"
610                                                                set identical "yes"
611                                                                copy ${dir1}/${fl} ${dir}
612                                                            }
613                                                        }
614                                                    }
615                                                    delete ${tempfile1} ${tempfile2} ${tempdir}
616                                                    if {${identical}=="no"} {
617                                                        return -code error "${prefixDir}/${fl} differs in ${base1} and ${base2} and cannot be merged"
618                                                    }
619                                                }
620                                                default {
621                                                    return -code error "${prefixDir}/${fl} differs in ${base1} and ${base2} and cannot be merged"
622                                                }
623                                            }
624                                        }
625                                    }
626                                }
627                            }
628                        }
629                    }
630                }
631            }
632        }
633
634        # /usr/bin/diff can merge two C/C++ files
635        # See http://www.gnu.org/software/diffutils/manual/html_mono/diff.html#If-then-else
636        # See http://www.gnu.org/software/diffutils/manual/html_mono/diff.html#Detailed%20If-then-else
637        set diffFormatProc {--old-group-format='#if (defined(__ppc__) || defined(__ppc64__))
638 %<#endif
639' \
640--new-group-format='#if defined (__i386__) || defined(__x86_64__)
641%>#endif
642' \
643--unchanged-group-format='%=' \
644--changed-group-format='#if (defined(__ppc__) || defined(__ppc64__))
645%<#else
646%>#endif
647'}
648
649        set diffFormatM "-D __LP64__"
650
651        if { ![info exists merger_dont_diff] } {
652            set merger_dont_diff {}
653        }
654
655        merge2Dir  ${workpath}/destroot-ppc      ${workpath}/destroot-ppc64 ${workpath}/destroot-powerpc  ""  ppc ppc64    ${merger_dont_diff}  ${diffFormatM}
656        merge2Dir  ${workpath}/destroot-i386     ${workpath}/destroot-x86_64 ${workpath}/destroot-intel   ""  i386 x86_64  ${merger_dont_diff}  ${diffFormatM}
657        merge2Dir  ${workpath}/destroot-powerpc  ${workpath}/destroot-intel ${workpath}/destroot          ""  powerpc x86  ${merger_dont_diff}  ${diffFormatProc}
658    }
659
660    test {
661        foreach arch ${universal_archs_to_use} {
662            # Rosetta does not translate G5 instructions
663            # PowerPC systems can't translate Intel instructions
664            if { (${os.arch}=="i386" && ${arch}!="ppc64") || (${os.arch}=="powerpc" && ${arch}!="i386" && ${arch}!="x86_64") } {
665                ui_info "$UI_PREFIX [format [msgcat::mc "Testing %1\$s for architecture %2\$s"] $name ${arch}]"
666                set test_dir_save ${test.dir}
667                if { [string match "${worksrcpath}/*" ${test.dir}] } {
668                    # The test directory is inside the source directory, so put in the new source directory name.
669                    eval test.dir  [string map "${worksrcpath} ${worksrcpath}-${arch}" ${test.dir}]
670                } else {
671                    # The test directory is outside the source directory, so give it a new name by appending ${arch}.
672                    test.dir  ${test.dir}-${arch}
673                    if { ![file exists ${test.dir}] } {
674                        file mkdir ${test.dir}
675                    }
676                }
677
678                porttest::test_main
679
680                test.dir ${test_dir_save}
681            }
682        }
683    }
684}
685
686# [muniversal_file_or_symlink_exists ${f}] tells you if ${f} exists. And unlike
687# [file exists ${f}], if used on a symlink, [muniversal_file_or_symlink_exists ${f}]
688# tells you about the symlink, not what it points to.
689proc muniversal_file_or_symlink_exists {f} {
690    # If [file type ${f}] throws an error, ${f} doesn't exist.
691    if {[catch {file type ${f}}]} {
692        return 0
693    }
694    # Otherwise, it does.
695    return 1
696}
Note: See TracBrowser for help on using the repository browser.