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

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

muniversal-1.0.tcl: Update muniversal_arch_flag_supported.

Now matches trunk's portconfigure::arch_flag_supported as of r103449.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 34.0 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 103450 2013-02-26 07:46:24Z larryv@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
89variant universal {
90    global universal_archs_to_use
91
92    foreach arch ${universal_archs} {
93        configure.universal_cflags-delete    -arch ${arch}
94        configure.universal_cxxflags-delete  -arch ${arch}
95        configure.universal_ldflags-delete   -arch ${arch}
96    }
97
98    eval configure.args-append      ${configure.universal_args}
99    eval configure.cflags-append    ${configure.universal_cflags}
100    eval configure.cxxflags-append  ${configure.universal_cxxflags}
101    eval configure.objcflags-append ${configure.universal_cflags}
102    eval configure.ldflags-append   ${configure.universal_ldflags}
103    eval configure.cppflags-append  ${configure.universal_cppflags}
104
105    # user has specified that build platform must be able to run binaries for supported architectures
106    if { ${merger_must_run_binaries}=="yes" } {
107        if { ${os.arch}=="i386" } {
108            set universal_archs_supported [ldelete ${universal_archs_supported} "ppc64"]
109            if {${os.major} >= 9 && [sysctl hw.cpu64bit_capable] == 0} {
110                set universal_archs_supported [ldelete ${universal_archs_supported} "x86_64"]
111            }
112        } else {
113            set universal_archs_supported [ldelete ${universal_archs_supported} "i386"]
114            set universal_archs_supported [ldelete ${universal_archs_supported} "x86_64"]
115            if {${os.major} >= 9 && [sysctl hw.cpu64bit_capable] == 0} {
116                set universal_archs_supported [ldelete ${universal_archs_supported} "ppc64"]
117            }
118        }
119    }
120
121    # set universal_archs_to_use as the intersection of universal_archs and universal_archs_supported
122    set universal_archs_to_use {}
123    foreach arch ${universal_archs} {
124        set arch_ok no
125        foreach archt ${universal_archs_supported} {
126            if { ${arch}==${archt} } {
127                set arch_ok yes
128            }
129        }
130        if { ${arch_ok}=="yes" } {
131            lappend universal_archs_to_use ${arch}
132        }
133    }
134
135    # if merger_no_3_archs is yes, prune universal_archs_to_use until it only has two elements
136    if { ${merger_no_3_archs}=="yes" } {
137        if { [llength ${universal_archs_to_use}] == 3 } {
138            # first try to remove cross-compiled 64-bit arch
139            if { ${os.arch}=="i386" } {
140                set universal_archs_to_use [ldelete ${universal_archs_to_use} "ppc64"]
141            } else {
142                set universal_archs_to_use [ldelete ${universal_archs_to_use} "x86_64"]
143            }
144        }
145        if { [llength ${universal_archs_to_use}] == 3 } {
146            # next try to remove cross-compiled 32-bit arch
147            if { ${os.arch}=="i386" } {
148                set universal_archs_to_use [ldelete ${universal_archs_to_use} "ppc"]
149            } else {
150                set universal_archs_to_use [ldelete ${universal_archs_to_use} "i386"]
151            }
152        }
153        if { [llength ${universal_archs_to_use}] == 3 } {
154            # at least one arch should have been removed from universal_archs_to_use
155            error "Should Not Happen"
156        }
157    }
158
159    configure {
160        # Fix inability to find nm when cross-compiling (#22224, #23431, #23687, #24477, et al)
161        configure.env-append    NM=/usr/bin/nm
162
163        foreach arch ${universal_archs_to_use} {
164            ui_info "$UI_PREFIX [format [msgcat::mc "Configuring %1\$s for architecture %2\$s"] $name ${arch}]"
165
166            copy ${worksrcpath} ${worksrcpath}-${arch}
167
168            set archf [muniversal_get_arch_flag ${arch}]
169            set archff [muniversal_get_arch_flag ${arch} "fortran"]
170
171            if { ${merger_arch_flag} != "no" } {
172                configure.cflags-append    ${archf}
173                configure.cxxflags-append  ${archf}
174                configure.objcflags-append ${archf}
175                configure.fflags-append    ${archff}
176                configure.fcflags-append   ${archff}
177                configure.f90flags-append  ${archff}
178                configure.ldflags-append   ${archf}
179            }
180
181            if { [info exists merger_configure_env(${arch})] } {
182                configure.env-append  $merger_configure_env(${arch})
183            }
184            if { [info exists merger_configure_cppflags(${arch})] } {
185                configure.cppflags-append  $merger_configure_cppflags(${arch})
186            }
187            if { [info exists merger_configure_cflags(${arch})] } {
188                configure.cflags-append  $merger_configure_cflags(${arch})
189            }
190            if { [info exists merger_configure_cxxflags(${arch})] } {
191                configure.cxxflags-append  $merger_configure_cxxflags(${arch})
192            }
193            if { [info exists merger_configure_objcflags(${arch})] } {
194                configure.objcflags-append  $merger_configure_objcflags(${arch})
195            }
196            if { [info exists merger_configure_ldflags(${arch})] } {
197                configure.ldflags-append  $merger_configure_ldflags(${arch})
198            }
199
200            # Don't set the --host unless we have to.
201            set host ""
202            if { [info exists merger_host($arch)] } {
203                if { $merger_host($arch) != "" } {
204                    set host  --host=$merger_host($arch)
205                }
206            } elseif {[file tail ${configure.cmd}] != "cmake"} {
207                # check if building for a word length we can't run
208                set bits_differ 0
209                if {(${arch}=="x86_64" || ${arch}=="ppc64") &&
210                    (${os.major} < 9 || [sysctl hw.cpu64bit_capable] == 0)} {
211                    set bits_differ 1
212                }
213                # check if building for a completely different arch
214                if {$bits_differ || (${os.arch}=="i386" && (${arch}=="ppc" || ${arch}=="ppc64"))
215                        || (${os.arch}=="powerpc" && (${arch}=="i386" || ${arch}=="x86_64"))
216                        || $macosx_deployment_target != $macosx_version} {
217                    if {$macosx_deployment_target == $macosx_version} {
218                        set hostversion ${os.version}
219                    } else {
220                        set hostversion [expr [lindex [split $macosx_deployment_target .] 1] + 4]
221                    }
222                    switch -- ${arch} {
223                        x86_64  {set host "--host=x86_64-apple-${os.platform}${hostversion}"}
224                        i386    {set host "--host=i686-apple-${os.platform}${hostversion}"}
225                        ppc     {set host "--host=powerpc-apple-${os.platform}${hostversion}"}
226                        ppc64   {set host "--host=powerpc64-apple-${os.platform}${hostversion}"}
227                    }
228                }
229            }
230            if {$host != ""} {
231                configure.args-append  ${host}
232            }
233
234            if { [info exists merger_configure_args(${arch})] } {
235                configure.args-append  $merger_configure_args(${arch})
236            }
237
238            set configure_compiler_save ${configure.compiler}
239            set configure_cc_save       ${configure.cc}
240            set configure_cxx_save      ${configure.cxx}
241            set configure_objc_save     ${configure.objc}
242            set configure_fc_save       ${configure.fc}
243            set configure_f77_save      ${configure.f77}
244            set configure_f90_save      ${configure.f90}
245
246            if { [info exists merger_configure_compiler($arch)] } {
247                configure.compiler  $merger_configure_compiler($arch)
248                configure.cc        [portconfigure::configure_get_compiler cc]
249                configure.cxx       [portconfigure::configure_get_compiler cxx]
250                configure.objc      [portconfigure::configure_get_compiler objc]
251                configure.f77       [portconfigure::configure_get_compiler f77]
252                configure.f90       [portconfigure::configure_get_compiler f90]
253                configure.fc        [portconfigure::configure_get_compiler fc]
254            }
255
256            if { ${merger_arch_compiler} != "no" } {
257                configure.cc   ${configure.cc}   ${archf}
258                configure.cxx  ${configure.cxx}  ${archf}
259                configure.objc ${configure.objc} ${archf}
260                if { ${configure.fc}  != "" } { configure.fc   ${configure.fc}  ${archff} }
261                if { ${configure.f77} != "" } { configure.f77  ${configure.f77} ${archff} }
262                if { ${configure.f90} != "" } { configure.f90  ${configure.f90} ${archff} }
263            }
264
265            set configure_dir_save  ${configure.dir}
266            if { [string match "${worksrcpath}/*" ${configure.dir}] } {
267                # The configure directory is inside the source directory, so put in the new source directory name.
268                eval configure.dir  [string map "${worksrcpath} ${worksrcpath}-${arch}" ${configure.dir}]
269            } else {
270                # The configure directory is outside the source directory, so give it a new name by appending ${arch}.
271                configure.dir  ${configure.dir}-${arch}
272                if { ![file exists ${configure.dir}] } {
273                    file mkdir ${configure.dir}
274                }
275            }
276
277            set autoreconf_dir_save  ${autoreconf.dir}
278            if { [string match "${worksrcpath}/*" ${autoreconf.dir}] } {
279                # The autoreconf directory is inside the source directory, so put in the new source directory name.
280                eval autoreconf.dir  [string map "${worksrcpath} ${worksrcpath}-${arch}" ${autoreconf.dir}]
281            } else {
282                # The autoreconf directory is outside the source directory, so give it a new name by appending ${arch}.
283                autoreconf.dir  ${autoreconf.dir}-${arch}
284                if { ![file exists ${autoreconf.dir}] } {
285                    file mkdir ${autoreconf.dir}
286                }
287            }
288
289            portconfigure::configure_main
290
291            # Undo changes to the configure related variables
292            eval autoreconf.dir ${autoreconf_dir_save}
293            eval configure.dir  ${configure_dir_save}
294            eval configure.compiler ${configure_compiler_save}
295            eval configure.f90  ${configure_f90_save}
296            eval configure.f77  ${configure_f77_save}
297            eval configure.fc   ${configure_fc_save}
298            eval configure.cc   ${configure_cc_save}
299            eval configure.cxx  ${configure_cxx_save}
300            eval configure.objc ${configure_objc_save}
301            if { [info exists merger_configure_args(${arch})] } {
302                configure.args-delete  $merger_configure_args(${arch})
303            }
304            configure.args-delete  ${host}
305            if { [info exists merger_configure_ldflags(${arch})] } {
306                configure.ldflags-delete  $merger_configure_ldflags(${arch})
307            }
308            if { [info exists merger_configure_cxxflags(${arch})] } {
309                configure.cxxflags-delete  $merger_configure_cxxflags(${arch})
310            }
311            if { [info exists merger_configure_objcflags(${arch})] } {
312                configure.objcflags-delete  $merger_configure_objcflags(${arch})
313            }
314            if { [info exists merger_configure_cflags(${arch})] } {
315                configure.cflags-delete  $merger_configure_cflags(${arch})
316            }
317            if { [info exists merger_configure_cppflags(${arch})] } {
318                configure.cppflags-delete  $merger_configure_cppflags(${arch})
319            }
320            if { [info exists merger_configure_env(${arch})] } {
321                configure.env-delete  $merger_configure_env(${arch})
322            }
323            if { ${merger_arch_flag} != "no" } {
324                configure.ldflags-delete   ${archf}
325                configure.f90flags-delete  ${archff}
326                configure.fcflags-delete   ${archff}
327                configure.fflags-delete    ${archff}
328                configure.objcflags-delete ${archf}
329                configure.cxxflags-delete  ${archf}
330                configure.cflags-delete    ${archf}
331            }
332        }
333    }
334
335    build {
336        foreach arch ${universal_archs_to_use} {
337            ui_info "$UI_PREFIX [format [msgcat::mc "Building %1\$s for architecture %2\$s"] $name ${arch}]"
338
339            if { [info exists merger_build_env(${arch})] } {
340                build.env-append  $merger_build_env(${arch})
341            }
342            if { [info exists merger_build_args(${arch})] } {
343                build.args-append  $merger_build_args(${arch})
344            }
345            set build_dir_save  ${build.dir}
346            if { [string match "${worksrcpath}/*" ${build.dir}] } {
347                # The build directory is inside the source directory, so put in the new source directory name.
348                eval build.dir  [string map "${worksrcpath} ${worksrcpath}-${arch}" ${build.dir}]
349            } else {
350                # The build directory is outside the source directory, so give it a new name by appending ${arch}.
351                build.dir  ${build.dir}-${arch}
352                if { ![file exists ${build.dir}] } {
353                    file mkdir ${build.dir}
354                }
355            }
356
357            portbuild::build_main
358
359            eval build.dir  ${build_dir_save}
360            if { [info exists merger_build_args(${arch})] } {
361                build.args-delete $merger_build_args(${arch})
362            }
363            if { [info exists merger_build_env(${arch})] } {
364                build.env-delete  $merger_build_env(${arch})
365            }
366        }
367    }
368
369    destroot {
370        foreach arch ${universal_archs_to_use} {
371            ui_info "$UI_PREFIX [format [msgcat::mc "Staging %1\$s into destroot for architecture %2\$s"] $name ${arch}]"
372            copy ${destroot} ${workpath}/destroot-${arch}
373            set destdirSave ${destroot.destdir}
374            eval destroot.destdir  [string map "${destroot} ${workpath}/destroot-${arch}" ${destroot.destdir}]
375
376            if { [info exists merger_destroot_env(${arch})] } {
377                destroot.env-append  $merger_destroot_env(${arch})
378            }
379            set destroot_dir_save ${destroot.dir}
380            if { [string match "${worksrcpath}/*" ${destroot.dir}] } {
381                # The destroot directory is inside the source directory, so put in the new source directory name.
382                eval destroot.dir  [string map "${worksrcpath} ${worksrcpath}-${arch}" ${destroot.dir}]
383            } else {
384                # The destroot directory is outside the source directory, so give it a new name by appending ${arch}.
385                destroot.dir  ${destroot.dir}-${arch}
386                if { ![file exists ${destroot.dir}] } {
387                    file mkdir ${destroot.dir}
388                }
389            }
390
391            portdestroot::destroot_main
392
393            destroot.dir  ${destroot_dir_save}
394            if { [info exists merger_destroot_env(${arch})] } {
395                destroot.env-delete  $merger_destroot_env(${arch})
396            }
397            eval destroot.destdir ${destdirSave}
398        }
399        delete ${destroot}
400
401        # Merge ${base1}/${prefixDir} and ${base2}/${prefixDir} into dir ${base}/${prefixDir}
402        #        arch1, arch2: names to prepend to files if a diff merge of two files is forbidden by merger_dont_diff
403        #    merger_dont_diff: list of files for which /usr/bin/diff ${diffFormat} will not merge correctly
404        #          diffFormat: format used by diff to merge two text files
405        proc merge2Dir {base1 base2 base prefixDir arch1 arch2 merger_dont_diff diffFormat} {
406            set dir1  ${base1}/${prefixDir}
407            set dir2  ${base2}/${prefixDir}
408            set dir   ${base}/${prefixDir}
409
410            xinstall -d -m 0755 ${dir}
411
412            foreach fl [glob -directory ${dir2} -tails -nocomplain *] {
413                if { ![muniversal_file_or_symlink_exists ${dir1}/${fl}] } {
414                    # File only exists in ${dir1}
415                    ui_debug "universal: merge: ${prefixDir}/${fl} only exists in ${base2}"
416                    copy ${dir2}/${fl} ${dir}
417                }
418            }
419            foreach fl [glob -directory ${dir1} -tails -nocomplain *] {
420                if { ![muniversal_file_or_symlink_exists ${dir2}/${fl}] } {
421                    # File only exists in ${dir2}
422                    ui_debug "universal: merge: ${prefixDir}/${fl} only exists in ${base1}"
423                    copy ${dir1}/${fl} ${dir}
424                } else {
425                    # File exists in ${dir1} and ${dir2}
426                    ui_debug "universal: merge: merging ${prefixDir}/${fl} from ${base1} and ${base2}"
427
428                    # Ensure files are of same type
429                    if { [file type ${dir1}/${fl}]!=[file type ${dir2}/${fl}] } {
430                        error "${dir1}/${fl} and ${dir2}/${fl} are of different types"
431                    }
432
433                    if { [file type ${dir1}/${fl}]=="link" } {
434                        # Files are links
435                        ui_debug "universal: merge: ${prefixDir}/${fl} is a link"
436
437                        # Ensure links don't point to different things
438                        if { [file readlink ${dir1}/${fl}]==[file readlink ${dir2}/${fl}] } {
439                            copy ${dir1}/${fl} ${dir}
440                        } else {
441                            error "${dir1}/${fl} and ${dir2}/${fl} point to different targets (can't merge them)"
442                        }
443                    } elseif { [file isdirectory ${dir1}/${fl}] } {
444                        # Files are directories (but not links), so recursively call function
445                        merge2Dir ${base1} ${base2} ${base} ${prefixDir}/${fl} ${arch1} ${arch2} ${merger_dont_diff} ${diffFormat}
446                    } else {
447                        # Files are neither directories nor links
448                        if { ! [catch {system "/usr/bin/cmp \"${dir1}/${fl}\" \"${dir2}/${fl}\" && /bin/cp -v \"${dir1}/${fl}\" \"${dir}\""}] } {
449                            # Files are byte by byte the same
450                            ui_debug "universal: merge: ${prefixDir}/${fl} is identical in ${base1} and ${base2}"
451                        } else {
452                            # Actually try to merge the files
453                            # First try lipo, then libtool
454                            if { ! [catch {system "/usr/bin/lipo -create \"${dir1}/${fl}\" \"${dir2}/${fl}\" -output \"${dir}/${fl}\""}] } {
455                                # lipo worked
456                                ui_debug "universal: merge: lipo created ${prefixDir}/${fl}"
457                            } elseif { ! [catch {system "/usr/bin/libtool \"${dir1}/${fl}\" \"${dir2}/${fl}\" -o \"${dir}/${fl}\""}] } {
458                                # libtool worked
459                                ui_debug "universal: merge: libtool created ${prefixDir}/${fl}"
460                            } else {
461                                # lipo and libtool have failed, so assume they are text files to be merged
462                                set dontdiff no
463                                foreach dont ${merger_dont_diff} {
464                                    if { ${dont}=="${prefixDir}/${fl}" } {
465                                        set dontdiff yes
466                                    }
467                                }
468                                if { ${dontdiff}==yes } {
469                                    # user has specified that diff does not work
470                                    # attempt to give each file a unique name and create a new file which includes one of the original depending on the arch
471
472                                    set fh [open ${dir}/${arch1}-${fl} w 0644]
473                                    puts ${fh} "#include \"${arch1}-${fl}\""
474                                    close ${fh}
475
476                                    set fh [open ${dir}/${arch2}-${fl} w 0644]
477                                    puts ${fh} "#include \"${arch2}-${fl}\""
478                                    close ${fh}
479
480                                    ui_debug "universal: merge: created ${prefixDir}/${fl} to include ${prefixDir}/${arch1}-${fl} ${prefixDir}/${arch1}-${fl}"
481
482                                    system "/usr/bin/diff -d ${diffFormat} \"${dir}/${arch1}-${fl}\" \"${dir}/${arch2}-${fl}\" > \"${dir}/${fl}\"; test \$? -le 1"
483
484                                    copy -force ${dir1}/${fl} ${dir}/${arch1}-${fl}
485                                    copy -force ${dir2}/${fl} ${dir}/${arch2}-${fl}
486                                } else {
487                                    set known_file "no"
488
489                                    # Text file on which diff will not give correct results.
490                                    switch -glob ${fl} {
491                                        *.mod {
492                                            # .mod files from Fortran modules.
493                                            # Create a sepcial module directory for each architecture.
494                                            # To find these modules, GFortran might require -M or -J.
495                                            set known_file "yes"
496                                            file mkdir ${dir}/mods32
497                                            file mkdir ${dir}/mods64
498                                            if { ${arch1}=="i386" || ${arch1}=="ppc" } {
499                                                copy ${dir1}/${fl} ${dir}/mods32
500                                                copy ${dir2}/${fl} ${dir}/mods64
501                                            } else {
502                                                copy ${dir2}/${fl} ${dir}/mods32
503                                                copy ${dir1}/${fl} ${dir}/mods64
504                                            }
505                                        }
506                                        *.la -
507                                        *.pc -
508                                        *-config {
509                                            return -code error "${prefixDir}/${fl} differs in ${base1} and ${base2} and cannot be merged"
510                                        }
511                                    }
512
513                                    if { ${known_file}=="no" } {
514                                        if { ! [catch {system "/usr/bin/diff -dw ${diffFormat} \"${dir1}/${fl}\" \"${dir2}/${fl}\" > \"${dir}/${fl}\"; test \$? -le 1"} ] } {
515                                            # diff worked
516                                            ui_debug "universal: merge: used diff to create ${prefixDir}/${fl}"
517                                        } else {
518                                            # File created by diff is invalid
519                                            delete ${dir}/${fl}
520
521                                            # nothing has worked so far.
522                                            switch -glob ${fl} {
523                                                *.jar {
524                                                    # jar files can be different because of timestamp
525                                                    ui_debug "universal: merge: ${prefixDir}/${fl} differs in ${base1} and ${base2}; assume timestamp difference"
526                                                    copy ${dir1}/${fl} ${dir}
527                                                }
528                                                *.elc {
529                                                    # elc files can be different because they record when and where they were built.
530                                                    ui_debug "universal: merge: ${prefixDir}/${fl} differs in ${base1} and ${base2}; assume trivial difference"
531                                                    copy ${dir1}/${fl} ${dir}
532                                                }
533                                                *.gz -
534                                                *.bz2 {
535                                                    # compressed files can differ due to entropy
536                                                    switch -glob ${fl} {
537                                                        *.gz {
538                                                            set cat /usr/bin/gzcat
539                                                        }
540                                                        *.bz2 {
541                                                            set cat /usr/bin/bzcat
542                                                        }
543                                                    }
544                                                    set tempdir [mkdtemp "/tmp/muniversal.XXXXXXXX"]
545                                                    set tempfile1 "${tempdir}/${arch1}-[file rootname ${fl}]"
546                                                    set tempfile2 "${tempdir}/${arch2}-[file rootname ${fl}]"
547                                                    system "${cat} \"${dir1}/${fl}\" > \"${tempfile1}\""
548                                                    system "${cat} \"${dir2}/${fl}\" > \"${tempfile2}\""
549                                                    set identical "no"
550                                                    if { ! [catch {system "/usr/bin/cmp -s \"${tempfile1}\" \"${tempfile2}\""}] } {
551                                                        # files are identical
552                                                        ui_debug "universal: merge: ${prefixDir}/${fl} differs in ${base1} and ${base2} but the contents are the same"
553                                                        set identical "yes"
554                                                        copy ${dir1}/${fl} ${dir}
555                                                    }
556                                                    if { ${identical}=="no" } {
557                                                        switch -glob ${fl} {
558                                                            *.el.gz {
559                                                                # Emacs lisp files should be same across architectures
560                                                                # the emacs package (and perhaps others) records the date of automatically generated el files
561                                                                ui_debug "universal: merge: ${prefixDir}/${fl} differs in ${base1} and ${base2}; assume trivial difference"
562                                                                set identical "yes"
563                                                                copy ${dir1}/${fl} ${dir}
564                                                            }
565                                                        }
566                                                    }
567                                                    delete ${tempfile1} ${tempfile2} ${tempdir}
568                                                    if {${identical}=="no"} {
569                                                        return -code error "${prefixDir}/${fl} differs in ${base1} and ${base2} and cannot be merged"
570                                                    }
571                                                }
572                                                default {
573                                                    return -code error "${prefixDir}/${fl} differs in ${base1} and ${base2} and cannot be merged"
574                                                }
575                                            }
576                                        }
577                                    }
578                                }
579                            }
580                        }
581                    }
582                }
583            }
584        }
585
586        # /usr/bin/diff can merge two C/C++ files
587        # See http://www.gnu.org/software/diffutils/manual/html_mono/diff.html#If-then-else
588        # See http://www.gnu.org/software/diffutils/manual/html_mono/diff.html#Detailed%20If-then-else
589        set diffFormatProc {--old-group-format='#if (defined(__ppc__) || defined(__ppc64__))
590 %<#endif
591' \
592--new-group-format='#if defined (__i386__) || defined(__x86_64__)
593%>#endif
594' \
595--unchanged-group-format='%=' \
596--changed-group-format='#if (defined(__ppc__) || defined(__ppc64__))
597%<#else
598%>#endif
599'}
600
601        set diffFormatM "-D __LP64__"
602
603        if { ![info exists merger_dont_diff] } {
604            set merger_dont_diff {}
605        }
606
607        merge2Dir  ${workpath}/destroot-ppc      ${workpath}/destroot-ppc64 ${workpath}/destroot-powerpc  ""  ppc ppc64    ${merger_dont_diff}  ${diffFormatM}
608        merge2Dir  ${workpath}/destroot-i386     ${workpath}/destroot-x86_64 ${workpath}/destroot-intel   ""  i386 x86_64  ${merger_dont_diff}  ${diffFormatM}
609        merge2Dir  ${workpath}/destroot-powerpc  ${workpath}/destroot-intel ${workpath}/destroot          ""  powerpc x86  ${merger_dont_diff}  ${diffFormatProc}
610    }
611
612    test {
613        foreach arch ${universal_archs_to_use} {
614            # Rosetta does not translate G5 instructions
615            # PowerPC systems can't translate Intel instructions
616            if { (${os.arch}=="i386" && ${arch}!="ppc64") || (${os.arch}=="powerpc" && ${arch}!="i386" && ${arch}!="x86_64") } {
617                ui_info "$UI_PREFIX [format [msgcat::mc "Testing %1\$s for architecture %2\$s"] $name ${arch}]"
618                set test_dir_save ${test.dir}
619                if { [string match "${worksrcpath}/*" ${test.dir}] } {
620                    # The test directory is inside the source directory, so put in the new source directory name.
621                    eval test.dir  [string map "${worksrcpath} ${worksrcpath}-${arch}" ${test.dir}]
622                } else {
623                    # The test directory is outside the source directory, so give it a new name by appending ${arch}.
624                    test.dir  ${test.dir}-${arch}
625                    if { ![file exists ${test.dir}] } {
626                        file mkdir ${test.dir}
627                    }
628                }
629
630                porttest::test_main
631
632                test.dir ${test_dir_save}
633            }
634        }
635    }
636}
637
638# [muniversal_file_or_symlink_exists ${f}] tells you if ${f} exists. And unlike
639# [file exists ${f}], if used on a symlink, [muniversal_file_or_symlink_exists ${f}]
640# tells you about the symlink, not what it points to.
641proc muniversal_file_or_symlink_exists {f} {
642    # If [file type ${f}] throws an error, ${f} doesn't exist.
643    if {[catch {file type ${f}}]} {
644        return 0
645    }
646    # Otherwise, it does.
647    return 1
648}
Note: See TracBrowser for help on using the repository browser.