2 eval 'exec perl -S $0 ${1+"$@"}'
6 # This file is part of the LibreOffice project.
8 # This Source Code Form is subject to the terms of the Mozilla Public
9 # License, v. 2.0. If a copy of the MPL was not distributed with this
10 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
12 # This file incorporates work covered by the following license notice:
14 # Licensed to the Apache Software Foundation (ASF) under one or more
15 # contributor license agreements. See the NOTICE file distributed
16 # with this work for additional information regarding copyright
17 # ownership. The ASF licenses this file to you under the Apache
18 # License, Version 2.0 (the "License"); you may not use this file
19 # except in compliance with the License. You may obtain a copy of
20 # the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #*************************************************************************
24 # This app makes it easy to link a live build
25 # set into an install set. Then your devel iteration
26 # is: 'build', execute.
28 #*************************************************************************
34 use File::Spec::Functions qw[splitdir catdir];
36 # ends up in program/ooenv
37 ( my $moz_lib = `pkg-config --variable=libdir mozilla-nss` ) =~ tr/\n/:/;
39 java_path=`$thisdir/../ure-link/bin/javaldx 2>/dev/null`
40 export LD_LIBRARY_PATH="$thisdir:$java_path:' . $moz_lib . '$LD_LIBRARY_PATH"
42 export PATH="$thisdir:$thisdir/../ure-link/bin:$PATH"
43 export GNOME_DISABLE_CRASH_DIALOG=1
44 # debugging assistance
45 export SAL_DISABLE_FLOATGRAB=1
46 export G_SLICE=always-malloc
47 export MALLOC_CHECK_=2
48 export MALLOC_PERTURB_=153
49 export OOO_DISABLE_RECOVERY=1
50 export SAL_ALLOW_LINKOO_SYMLINKS=1
65 if ($ENV{'OS'} eq 'MACOSX') {
66 print "FIXME: linkoo currently does not work on Mac OS X\n";
74 if ($a =~ /--dry-run/) {
76 } elsif (($a eq '--help') || ($a eq '-h')) {
78 } elsif ($a eq '--backup') {
80 } elsif ($a eq '--copy') {
83 } elsif (!defined $OOO_INSTALL) {
85 } elsif (!defined $OOO_BUILD) {
88 print "Unknown argument '$a'\n";
93 if (!defined $OOO_BUILD && defined $ENV{SRC_ROOT}) {
94 $OOO_BUILD = $ENV{SRC_ROOT};
97 if ($usage || !defined $OOO_INSTALL || !defined $OOO_BUILD) {
98 printf "Usage: linkoo </path/to/ooo/install> [</path/to/ooo/build/tree>] [--dry-run] [--backup] [--copy]\n";
102 File::Spec->file_name_is_absolute($OOO_INSTALL) || die "linkoo requires absolute paths ($OOO_INSTALL does not qualify)";
103 File::Spec->file_name_is_absolute($OOO_BUILD) || die "linkoo requires absolute paths ($OOO_BUILD does not qualify)";
105 -d $OOO_INSTALL || die "No such directory $OOO_INSTALL";
106 -w $OOO_INSTALL || die "You need write access to $OOO_INSTALL";
107 -d $OOO_BUILD || die "No such directory $OOO_BUILD";
109 ($TARGET, $LIBVER, $LANG) = sniff_target ($OOO_BUILD);
111 $SOLARVER = "$OOO_BUILD/solver";
113 if ($TARGET =~ /^wntgcci/ || $TARGET =~ /^wntmsci[0-9]+/) {
117 if ($TARGET =~ /^wntmsci[0-9]+/) {
118 # wntgcci means are cross-compiling & can symlink, so copy only on real
123 # setup global variables
124 my $brand_program_dir = 'program';
125 my $ure_lib_dir = 'ure-link/lib';
126 my $win_ure_lib_dir = 'URE/bin';
128 my @exceptions = ( 'libsunjavaplugin', 'libjvmfwk' );
129 push @exceptions, 'cppuhelper' if (!$windows);
132 $bin = "|\\.bin" if ($windows);
134 $brand_program_dir => "(\\.so|\\.dll|\\.exe|\\.com$bin)\$",
135 $ure_lib_dir => "(\\.so\$|\\.so\\.3\$)",
136 $win_ure_lib_dir => "(\\.dll|\\.exe|\\.bin|\\.com)\$",
137 $brand_program_dir . '/resource' => '\.res$',
138 $brand_program_dir . '/classes' => '\.jar$',
139 'ure-link/share/java' => '\.jar$',
140 'share/extensions/nlpsolver' => '\.jar$',
141 'share/extensions/wiki-publisher' => '\.jar$',
142 'share/extensions/pdf-import' => "(\\.so|\\.dll|\\.exe|\\.com$bin)\$",
143 'share/extensions/presenter-screen' => "(\\.so|\\.dll|\\.exe|\\.com$bin)\$",
144 'share/extensions/presentation-minimizer' => "(\\.so|\\.dll|\\.exe|\\.com$bin)\$",
145 'share/config' => '\.zip$',
146 # 'share/uno_packages' => '\.zip$'
149 my @instdir_replaceable = (
152 # 'presets', # leave these guys alone for now
156 my @search_dirs = ( 'lib', 'bin', 'class' );
158 my @known_duplicates = ( 'db.jar', 'libi18n', 'libnssckbi', 'libnssdbm', 'libsqlite3', 'libnssutil3', 'pythonloader.uno', 'pyuno', 'libpyuno' );
162 my $build_dir = shift;
163 my ($target, $libver, $lang) = ( 'unxlngi6.pro', '680', 'en-US' ); # defaults
165 chomp($target=`cat $build_dir/config_host.mk | grep INPATH= | sed -e 's/.*=//' | sed -e 's/"//g'`);
166 chomp($libver=`cat $build_dir/config_host.mk | grep UPD= | sed -e 's/.*=//' | sed -e 's/"//g'`);
168 print "Sniffed target: $target, $libver\n";
170 return ($target, $libver, $lang);
173 sub build_installed_list($)
178 for my $suffix (keys %replaceable) {
179 my $dirname = "$path/$suffix";
181 my $pattern = $replaceable{$suffix};
182 if (opendir ($dirhandle, $dirname)) {
183 while (my $fname = readdir ($dirhandle)) {
184 $fname =~ m/$pattern/ || next;
187 for $pattern (@exceptions) {
188 $fname =~ /$pattern/ || next;
191 $files{$fname} = $dirname if !$skip;
193 closedir ($dirhandle);
195 print "Couldn't find '$dirname': skipping\n";
201 sub check_create_linked($)
204 my $linked_dir = "$path/linked";
205 if (! -d $linked_dir) {
206 mkdir $linked_dir || die "Can't make $linked_dir: $!";
214 my $src_name = shift;
215 my $dest_name = shift;
216 my $dont_check_link = shift;
218 if ($copy) { # copy if older ...
219 my $src_mtime = stat("$src/$src_name")->mtime;
220 my $dest_mtime = stat("$dest/$dest_name")->mtime;
221 if ($src_mtime > $dest_mtime) {
222 # print " copy $src/$src_name ($src_mtime) -> $dest/$dest_name ($dest_mtime)\n";
223 print " copy $src/$src_name -> $dest/$dest_name\n";
224 unlink ("$dest/$dest_name");
225 copy("$src/$src_name", "$dest/$dest_name") || die "Failed top copy: $!";
227 # print " up-to-date $src/$src_name -> $dest/$dest_name\n";
229 } elsif (-l "$dest/$dest_name" ) {
230 my $link = readlink ("$dest/$dest_name");
231 if ($link =~ /^\//) { # Absolute path
234 unlink ("$dest/$dest_name");
235 symlink ("$src/$src_name", "$dest/$dest_name") || die "Failed to symlink $src/$src_name: $!";
236 print " [$dest_name]";
238 print "re-make link $src/$src_name => $dest/$dest_name\n";
241 print "skipping symbolic link $dest/$dest_name -> $link\n";
245 # move / write the link
247 check_create_linked ($dest);
248 rename ("$dest/$dest_name", "$dest/linked/$dest_name") ||
249 defined $dont_check_link || die "Failed rename of $dest/$dest_name: $!";
251 unlink ("$dest/$dest_name") ||
252 defined $dont_check_link || die "Failed remove of $dest/$dest_name: $!";
254 symlink ("$src/$src_name", "$dest/$dest_name") || die "Failed to symlink $src/$src_name: $!";
257 print "move / symlink $src/$src_name => $dest/$dest_name\n";
262 sub scan_one_dir($$$$)
264 my ($installed_files, $build_files, $path, $solver) = @_;
268 if (opendir ($dirh_module, "$path/..")) {
269 while (my $file = readdir ($dirh_module)) {
270 if ($file =~ /Library_.*\.mk/) {
272 print STDERR "gnu-makeified module contains stale output dir '$path', renaming it away\n";
273 rename ($path, "$path.obsolete"); # if it fails, nevermind ...
278 closedir ($dirh_module);
282 for my $elem (@search_dirs) {
283 my $module_path = "$path/$elem";
284 if (opendir ($dirh_module, $module_path)) {
285 while (my $file = readdir ($dirh_module)) {
286 if (defined $installed_files->{$file}) {
287 if (defined $build_files->{$file}) {
289 for my $regexp (@known_duplicates) {
290 if ($file =~ m/$regexp/) {
294 if (!$known && !$solver) {
295 print STDERR "\nlinkoo:: Unknown duplicate file '$file' in: '" .
296 $build_files->{$file} . "' vs '" .
297 $module_path . "' in module $path\n";
301 $build_files->{$file} = $module_path;
306 closedir ($dirh_module);
312 my $build_path = shift;
317 opendir ($dirh_toplevel, $build_path) || die "Can't open '$build_path': $!";
318 while ( my $subdir = readdir ($dirh_toplevel) )
320 $subdir =~ m/\./ && next; # eg. vcl.old,
321 $subdir eq 'solver' && next; # skip solver dir itself
322 my $test = "$build_path/$subdir/$target";
324 push @modules, $test;
326 closedir ($dirh_toplevel);
331 sub scan_and_link_files($$$)
333 my $build_path = shift;
334 my $installed_files = shift;
337 my @modules = get_modules( $build_path, $target );
339 # Scan the old-style module/$target/lib directories ...
341 for my $module (@modules) {
342 scan_one_dir ($installed_files, \%build_files, $module, 0);
345 # Now scan the solver
346 scan_one_dir ($installed_files, \%build_files, "$SOLARVER/$target", 1);
348 for my $file (keys %build_files) {
349 my $src = $build_files{$file};
350 my $dest = $installed_files->{$file};
352 do_link ($src, $dest, $file, $file);
360 my $name = 'librecentfile.so';
361 my $src = "$OOO_BUILD/shell/$TARGET/lib/$name";
362 my $dest = "$OOO_BUILD/sfx2/$TARGET/lib/$name";
364 return if ($windows);
366 if ($doit eq 'undo') {
368 print " unlink $name\n";
372 $doit eq 'do' || die;
374 print " link $name\n";
380 sub do_link_gdb_py($$$)
386 my $lib = $loader =~ s/-gdb.py$//;
387 my $destdir = $libdir;
388 # Autoloader for a library is looked for in the same directory the library
389 # is (the library, not a symlink to it). Therefore it does not help to link
390 # it from solver into install, because there is only a symlink in install
391 # anyway. Instead, we must follow the link.
392 if (-l "$libdir/$lib") {
393 $destdir = readlink ("$libdir/$lib");
394 $destdir =~ s@/[^/]*$@@;
397 if ($destdir ne $srcdir) {
398 do_link ($srcdir, $destdir, $loader, $loader, 1);
404 return if ($windows);
405 print "Special gdb.py helpers case: ";
410 my $src = "$SOLARVER/$TARGET/lib";
411 opendir ($dirh, $src) || die "can't open solver: $src: $!";
412 while (my $dent = readdir ($dirh)) {
413 $dent =~ /^\./ && next;
414 $dent =~ /\-gdb\.py/ || next;
415 if ($dent =~ /uno/) {
422 if (@ure < 1 || @basis < 1) {
423 print STDERR "Warning: missing helpful python debug helpers\n";
426 do_link_gdb_py ($src, "$OOO_INSTALL/program", $c);
429 do_link_gdb_py ($src, "$OOO_INSTALL/ure/lib", $c);
435 sub link_pagein_files()
437 return if ($windows);
439 print "pagein case:";
440 my $src = "$SOLARVER/$TARGET/bin";
441 my $dest = "$OOO_INSTALL/" . $brand_program_dir;
442 for my $c ('calc', 'draw', 'impress', 'writer', 'common') {
443 do_link ($src, $dest, "pagein-$c", "pagein-$c");
450 # First find all the en-US .ui files installed
455 if ( $File::Find::dir !~ /\/res\// && $_ =~ /\.ui$/ )
457 push( @files, $File::Find::name );
459 }, "$OOO_INSTALL/" );
461 my @modules = get_modules( $OOO_BUILD, $TARGET );
464 # Search the files in the source tree
465 for my $dest ( @files )
467 my @dest_dirs = splitdir( $dest );
468 my $module_dir = @dest_dirs[-3];
470 my $name = @dest_dirs[-1];
471 my $nb_dirs = @dest_dirs - 2;
472 my $dest_dir = catdir( @dest_dirs[0..$nb_dirs] );
474 # Find out the file to link to in the source tree
477 if ( $dest =~ /\/modules\// )
479 # Handle the modules/* cases
480 if ( $module_dir =~ /^sw/ || $module_dir eq "sglobal" ) { $modulepath = "sw/uiconfig"; }
481 elsif ( $module_dir eq "smath" ) { $modulepath = "starmath/uiconfig"; }
482 elsif ( $module_dir eq "simpress" || $module_dir eq "sdraw" ) { $modulepath = "sd/uiconfig"; }
483 elsif ( $module_dir eq "scalc" ) { $modulepath = "sc/uiconfig"; }
484 elsif ( $module_dir =~ /^db/ ) { $modulepath = "dbaccess/uiconfig"; }
485 elsif ( $module_dir eq "BasicIDE" ) { $modulepath = "basctl/uiconfig/basicide"; $nb_segments = 2; }
486 elsif ( $module_dir eq "schart" ) { $modulepath = "chart2/uiconfig"; $nb_segments = 2; }
487 elsif ( $module_dir eq "tubes" ) { $modulepath = "tubes/uiconfig"; }
488 elsif ( $module_dir eq "StartModule" ) { $modulepath = "framework/uiconfig/startmodule"; $nb_segments = 2; }
493 # Handle the <module>/ui/ cases
494 my $module = $module_dir;
495 if ( $module_dir eq "sfx" ) { $module = "sfx2"; }
496 elsif ( $module_dir eq "svt" ) { $module = "svtools"; }
497 elsif ( $module_dir eq "sw" ) { $module = "sw"; $nb_segments = 3; }
498 elsif ( $module_dir eq "spa" ) { $module = "padmin"; }
499 elsif ( $module_dir eq "xmlsec" ) { $module = "xmlsecurity"; }
501 $modulepath = "$module/uiconfig";
503 my $subpath = catdir( @dest_dirs[-$nb_segments..-2] );
504 my $src_dir = "$OOO_BUILD/$modulepath/$subpath";
506 # print STDERR "$module_dir : $modulepath : '$src_dir/$name'\n";
508 if ( -e "$src_dir/$name" )
510 do_link ( $src_dir, $dest_dir, $name, $name );
518 print "linking rdb:";
519 my $src_prefix = "$SOLARVER/$TARGET/";
520 my $dest_prefix = "$OOO_INSTALL/";
522 do_link ($src_prefix . "xml" , $dest_prefix . $brand_program_dir . "/services", "services.rdb", "services.rdb");
523 do_link ($src_prefix . "xml/ure" , $dest_prefix . "ure/share/misc", "services.rdb", "services.rdb");
525 do_link ($src_prefix . "bin" , $dest_prefix . "ure/share/misc", "udkapi.rdb", "types.rdb");
530 # instdir is an internal directory in the build tree
531 # installdir is the directory we installed into.
532 sub do_recursive_link($$)
534 my ($instdir, $installdir) = @_;
536 (-d $installdir && -d $instdir) || die "not directories";
539 if (opendir ($dirhandle, $instdir)) {
540 while (my $fname = readdir ($dirhandle)) {
541 $fname =~ /^\./ && next;
542 if (-d "$instdir/$fname") {
543 if (-d "$installdir/$fname") {
544 do_recursive_link("$instdir/$fname", "$installdir/$fname");
546 print STDERR "mismatching directories $instdir/$fname vs. $installdir/$fname\n";
548 } elsif (-f "$installdir/$fname") {
549 do_link ($instdir, $installdir, $fname, $fname, 0);
551 print STDERR "Warning: odd file type for $instdir/$fname\n";
555 print STDERR "Couldn't scan '$instdir': $!";
561 my ($instdir, $installdir) = @_;
563 print "linking instdir ...\n";
564 for my $dir (@instdir_replaceable) {
566 do_recursive_link("$instdir/$dir", "$installdir/$dir");
572 my $installed_files = build_installed_list ($OOO_INSTALL);
574 scan_and_link_files ($OOO_BUILD, $installed_files, $TARGET);
575 link_instdir("$OOO_BUILD/instdir/$TARGET", $OOO_INSTALL);
581 if (!-f "$OOO_INSTALL/" . $brand_program_dir . "/ooenv") {
583 print "Creating '$OOO_INSTALL/", $brand_program_dir, "/ooenv'\n";
584 open ($ooenv, ">$OOO_INSTALL/" . $brand_program_dir . "/ooenv") || die "Can't open $OOO_INSTALL/" . $brand_program_dir . "/ooenv: $!";
585 print $ooenv "thisdir=$OOO_INSTALL/" . $brand_program_dir . "/\n";
586 print $ooenv $env_script;
592 print "\nlinkoo finished\n";
594 # vim:set shiftwidth=4 softtabstop=4 expandtab: