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