xref: /openbsd-src/usr.bin/libtool/LT/Mode/Link.pm (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1# ex:ts=8 sw=4:
2# $OpenBSD: Link.pm,v 1.19 2012/07/13 13:25:12 espie Exp $
3#
4# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
5# Copyright (c) 2012 Marc Espie <espie@openbsd.org>
6#
7# Permission to use, copy, modify, and distribute this software for any
8# purpose with or without fee is hereby granted, provided that the above
9# copyright notice and this permission notice appear in all copies.
10#
11# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18use strict;
19use warnings;
20use feature qw(say);
21
22# supplement OSConfig with stuff needed.
23package LT::OSConfig;
24
25my ($search_dir_hash, $search_dir_list);
26sub fillup_search_dirs
27{
28	return if defined $search_dir_list;
29	$search_dir_list = [];
30	$search_dir_hash = {};
31	open(my $fh, '-|', '/sbin/ldconfig -r');
32	if (!defined $fh) {
33		die "Can't run ldconfig\n";
34	}
35	while (<$fh>) {
36		if (m/^\s*search directories:\s*(.*?)\s*$/o) {
37			foreach my $d (split(/\:/o, $1)) {
38				push @$search_dir_list, $d;
39				$search_dir_hash->{$d} = 1;
40			}
41			last;
42		}
43	}
44	close($fh);
45}
46
47sub search_dirs
48{
49	my $self = shift;
50	$self->fillup_search_dirs;
51	return @$search_dir_list;
52}
53
54sub is_search_dir
55{
56	my ($self, $dir) = @_;
57	$self->fillup_search_dirs;
58	return $search_dir_hash->{$dir};
59}
60
61
62# let's add the libsearchdirs and -R options there
63package LT::Options;
64
65sub add_libsearchdir
66{
67	my $self = shift;
68	push(@{$self->{libsearchdir}}, @_);
69}
70
71sub libsearchdirs
72{
73	my $self = shift;
74	return @{$self->{libsearchdir}};
75}
76
77# -R options originating from .la resolution
78sub add_R
79{
80	my $self = shift;
81	push(@{$self->{Rresolved}}, @_);
82}
83
84sub Rresolved
85{
86	my $self = shift;
87	$self->{Rresolved} //= [];
88	return @{$self->{Rresolved}};
89}
90
91package LT::Mode::Link;
92our @ISA = qw(LT::Mode);
93
94use LT::Util;
95use LT::Trace;
96use LT::Library;
97use File::Basename;
98
99use constant {
100	OBJECT	=> 0, # unused ?
101	LIBRARY	=> 1,
102	PROGRAM	=> 2,
103};
104
105sub help
106{
107	print <<"EOH";
108
109Usage: $0 --mode=link LINK-COMMAND ...
110Link object files and libraries into a library or a program
111EOH
112}
113
114my $shared = 0;
115my $static = 1;
116
117sub run
118{
119	my ($class, $ltprog, $gp, $ltconfig) = @_;
120
121	my $noshared  = $ltconfig->noshared;
122	my $cmd;
123	my $libdirs = [];	# list of libdirs
124	my $libs = LT::Library::Stash->new;		# libraries
125	my $dirs = {};		# paths to find libraries
126	# put a priority in the dir hash
127	# always look here
128	$dirs->{'/usr/lib'} = 3;
129
130	$gp->handle_permuted_options(
131	    'all-static',
132	    'allow-undefined', # we don't care about THAT one
133	    'avoid-version',
134	    'dlopen:',
135	    'dlpreopen:',
136	    'export-dynamic',
137	    'export-symbols:',
138	    'export-symbols-regex:',
139	    'module',
140	    'no-fast-install',
141	    'no-install',
142	    'no-undefined',
143	    'o:!@',
144	    'objectlist:',
145	    'precious-files-regex:',
146	    'prefer-pic',
147	    'prefer-non-pic',
148	    'release:',
149	    'rpath:@',
150	    'L:!', sub { shortdie "libtool does not allow spaces in -L dir\n"},
151	    'R:@',
152	    'shrext:',
153	    'static',
154	    'thread-safe', # XXX and --thread-safe ?
155	    'version-info:',
156	    'version-number:');
157
158	# XXX options ignored: dlopen, dlpreopen, no-fast-install,
159	# 	no-install, no-undefined, precious-files-regex,
160	# 	shrext, thread-safe, prefer-pic, prefer-non-pic
161
162	my @RPopts = $gp->rpath;	 # -rpath options
163	my @Ropts = $gp->R;		 # -R options on the command line
164
165	# add the .libs dir as well in case people try to link directly
166	# with the real library instead of the .la library
167	$gp->add_libsearchdir(LT::OSConfig->search_dirs, './.libs');
168
169	if (!$gp->o) {
170		shortdie "No output file given.\n";
171	}
172	if ($gp->o > 1) {
173		shortdie "Multiple output files given.\n";
174	}
175
176	my $outfile = ($gp->o)[0];
177	tsay {"outfile = $outfile"};
178	my $odir = dirname($outfile);
179	my $ofile = basename($outfile);
180
181	# what are we linking?
182	my $linkmode = PROGRAM;
183	if ($ofile =~ m/\.l?a$/) {
184		$linkmode = LIBRARY;
185		$gp->handle_permuted_options('x:!');
186	}
187	tsay {"linkmode: $linkmode"};
188
189	# eat multiple version-info arguments, we only accept the first.
190	map { $_ = '' if ($_ =~ m/\d+:\d+:\d+/); } @ARGV;
191
192	my @objs;
193	my @sobjs;
194	if ($gp->objectlist) {
195		my $objectlist = $gp->objectlist;
196		open(my $ol, '<', $objectlist) or die "Cannot open $objectlist: $!\n";
197		my @objlist = <$ol>;
198		for (@objlist) { chomp; }
199		generate_objlist(\@objs, \@sobjs, \@objlist);
200	} else {
201		generate_objlist(\@objs, \@sobjs, \@ARGV);
202	}
203	tsay {"objs = @objs"};
204	tsay {"sobjs = @sobjs"};
205
206	my $deplibs = [];	# list of dependent libraries (both -L and -l flags)
207	my $parser = LT::Parser->new(\@ARGV);
208
209	if ($linkmode == PROGRAM) {
210		require LT::Mode::Link::Program;
211		my $program = LT::Program->new;
212		$program->{outfilepath} = $outfile;
213		# XXX give higher priority to dirs of not installed libs
214		if ($gp->export_dynamic) {
215			push(@{$parser->{args}}, "-Wl,-E");
216		}
217
218		$parser->parse_linkargs1($deplibs, $gp, $dirs, $libs);
219		tsay {"end parse_linkargs1"};
220		tsay {"deplibs = @$deplibs"};
221
222		$program->{objlist} = \@objs;
223		if (@objs == 0) {
224			if (@sobjs > 0) {
225				tsay {"no non-pic libtool objects found, trying pic objects..."};
226				$program->{objlist} = \@sobjs;
227			} elsif (@sobjs == 0) {
228				tsay {"no libtool objects of any kind found"};
229				tsay {"hoping for real objects in ARGV..."};
230			}
231		}
232		my $RPdirs = [];
233		@$RPdirs = (@Ropts, @RPopts, $gp->Rresolved);
234		$program->{RPdirs} = $RPdirs;
235
236		$program->link($ltprog, $ltconfig, $dirs, $libs, $deplibs, $libdirs, $parser, $gp);
237	} elsif ($linkmode == LIBRARY) {
238		my $convenience = 0;
239		require LT::Mode::Link::Library;
240		my $lainfo = LT::LaFile->new;
241
242		$shared = 1 if ($gp->version_info ||
243				$gp->avoid_version ||
244				$gp->module);
245		if (!@RPopts) {
246			$convenience = 1;
247			$noshared = 1;
248			$static = 1;
249			$shared = 0;
250		} else {
251			$shared = 1;
252		}
253		if ($ofile =~ m/\.a$/ && !$convenience) {
254			$ofile =~ s/\.a$/.la/;
255			$outfile =~ s/\.a$/.la/;
256		}
257		(my $libname = $ofile) =~ s/\.l?a$//;	# remove extension
258		my $staticlib = $libname.'.a';
259		my $sharedlib = $libname.'.so';
260		my $sharedlib_symlink;
261
262		if ($gp->static || $gp->all_static) {
263			$shared = 0;
264			$static = 1;
265		}
266		$shared = 0 if $noshared;
267
268		$parser->parse_linkargs1($deplibs, $gp, $dirs, $libs);
269		tsay {"end parse_linkargs1"};
270		tsay {"deplibs = @$deplibs"};
271
272		my $sover = '0.0';
273		my $origver = 'unknown';
274		# environment overrides -version-info
275		(my $envlibname = $libname) =~ s/[.+-]/_/g;
276		my ($current, $revision, $age) = (0, 0, 0);
277		if ($gp->version_info) {
278			($current, $revision, $age) = parse_version_info($gp->version_info);
279			$origver = "$current.$revision";
280			$sover = $origver;
281		}
282		if ($ENV{"${envlibname}_ltversion"}) {
283			# this takes priority over the previous
284			$sover = $ENV{"${envlibname}_ltversion"};
285			($current, $revision) = split /\./, $sover;
286			$age = 0;
287		}
288		if (defined $gp->release) {
289			$sharedlib_symlink = $sharedlib;
290			$sharedlib = $libname.'-'.$gp->release.'.so';
291		}
292		if ($gp->avoid_version ||
293			(defined $gp->release && !$gp->version_info)) {
294			# don't add a version in these cases
295		} else {
296			$sharedlib .= ".$sover";
297			if (defined $gp->release) {
298				$sharedlib_symlink .= ".$sover";
299			}
300		}
301
302		# XXX add error condition somewhere...
303		$static = 0 if $shared && $gp->has_tag('disable-static');
304		$shared = 0 if $static && $gp->has_tag('disable-shared');
305
306		tsay {"SHARED: $shared\nSTATIC: $static"};
307
308		$lainfo->{'libname'} = $libname;
309		if ($shared) {
310			$lainfo->{'dlname'} = $sharedlib;
311			$lainfo->{'library_names'} = $sharedlib;
312			$lainfo->{'library_names'} .= " $sharedlib_symlink"
313				if defined $gp->release;
314			$lainfo->link($ltprog, $ltconfig, $ofile, $sharedlib, $odir, 1, \@sobjs, $dirs, $libs, $deplibs, $libdirs, $parser, $gp);
315			tsay {"sharedlib: $sharedlib"};
316			$lainfo->{'current'} = $current;
317			$lainfo->{'revision'} = $revision;
318			$lainfo->{'age'} = $age;
319		}
320		if ($static) {
321			$lainfo->{'old_library'} = $staticlib;
322			$lainfo->link($ltprog, $ltconfig, $ofile, $staticlib, $odir, 0, ($convenience && @sobjs > 0) ? \@sobjs : \@objs, $dirs, $libs, $deplibs, $libdirs, $parser, $gp);
323			tsay {($convenience ? "convenience" : "static"),
324			    " lib: $staticlib"};
325		}
326		$lainfo->{installed} = 'no';
327		$lainfo->{shouldnotlink} = $gp->module ? 'yes' : 'no';
328		map { $_ = "-R$_" } @Ropts;
329		unshift @$deplibs, @Ropts if @Ropts;
330		tsay {"deplibs = @$deplibs"};
331		my $finaldeplibs = reverse_zap_duplicates_ref($deplibs);
332		tsay {"finaldeplibs = @$finaldeplibs"};
333		$lainfo->set('dependency_libs', "@$finaldeplibs");
334		if (@RPopts) {
335			if (@RPopts > 1) {
336				tsay {"more than 1 -rpath option given, ",
337				    "taking the first: ", $RPopts[0]};
338			}
339			$lainfo->{'libdir'} = $RPopts[0];
340		}
341		if (!($convenience && $ofile =~ m/\.a$/)) {
342			$lainfo->write($outfile, $ofile);
343			unlink("$odir/$ltdir/$ofile");
344			symlink("../$ofile", "$odir/$ltdir/$ofile");
345		}
346		my $lai = "$odir/$ltdir/$ofile".'i';
347		if ($shared) {
348			my $pdeplibs = process_deplibs($finaldeplibs);
349			if (defined $pdeplibs) {
350				$lainfo->set('dependency_libs', "@$pdeplibs");
351			}
352			if (! $gp->module) {
353				$lainfo->write_shared_libs_log($origver);
354			}
355		}
356		$lainfo->{'installed'} = 'yes';
357		# write .lai file (.la file that will be installed)
358		$lainfo->write($lai, $ofile);
359	}
360}
361
362# populate arrays of non-pic and pic objects and remove these from @ARGV
363sub generate_objlist
364{
365	my $objs = shift;
366	my $sobjs = shift;
367	my $objsource = shift;
368
369	my $result = [];
370	foreach my $a (@$objsource) {
371		if ($a =~ m/\S+\.lo$/) {
372			require LT::LoFile;
373			my $ofile = basename($a);
374			my $odir = dirname($a);
375			my $loinfo = LT::LoFile->parse($a);
376			if ($loinfo->{'non_pic_object'}) {
377				my $o;
378				$o .= "$odir/" if ($odir ne '.');
379				$o .= $loinfo->{'non_pic_object'};
380				push @$objs, $o;
381			}
382			if ($loinfo->{'pic_object'}) {
383				my $o;
384				$o .= "$odir/" if ($odir ne '.');
385				$o .= $loinfo->{'pic_object'};
386				push @$sobjs, $o;
387			}
388		} elsif ($a =~ m/\S+\.o$/) {
389			push @$objs, $a;
390		} else {
391			push @$result, $a;
392		}
393	}
394	@$objsource = @$result;
395}
396
397# convert 4:5:8 into a list of numbers
398sub parse_version_info
399{
400	my $vinfo = shift;
401
402	if ($vinfo =~ m/^(\d+):(\d+):(\d+)$/) {
403		return ($1, $2, $3);
404	} elsif ($vinfo =~ m/^(\d+):(\d+)$/) {
405		return ($1, $2, 0);
406	} elsif ($vinfo =~ m/^(\d+)$/) {
407		return ($1, 0, 0);
408	} else {
409		die "Error parsing -version-info $vinfo\n";
410	}
411}
412
413# prepare dependency_libs information for the .la file which is installed
414# i.e. remove any .libs directories and use the final libdir for all the
415# .la files
416sub process_deplibs
417{
418	my $linkflags = shift;
419
420	my $result;
421
422	foreach my $lf (@$linkflags) {
423		if ($lf =~ m/-L\S+\Q$ltdir\E$/) {
424		} elsif ($lf =~ m/-L\./) {
425		} elsif ($lf =~ m/\/\S+\/(\S+\.la)/) {
426			my $lafile = $1;
427			require LT::LaFile;
428			my $libdir = LT::LaFile->parse($lf)->{'libdir'};
429			if ($libdir eq '') {
430				# this drops libraries which will not be
431				# installed
432				# XXX improve checks when adding to deplibs
433				say "warning: $lf dropped from deplibs";
434			} else {
435				$lf = $libdir.'/'.$lafile;
436				push @$result, $lf;
437			}
438		} else {
439			push @$result, $lf;
440		}
441	}
442	return $result;
443}
444
445package LT::Parser;
446use File::Basename;
447use Cwd qw(abs_path);
448use LT::Util;
449use LT::Trace;
450
451my $calls = 0;
452
453sub build_cache
454{
455	my ($self, $lainfo, $level) = @_;
456	my $o = $lainfo->{cached} = {
457	    deplibs => [], libdirs => [], result => []};
458	$self->internal_resolve_la($o, $lainfo->deplib_list,
459	    $level+1);
460	push(@{$o->{deplibs}}, @{$lainfo->deplib_list});
461	if ($lainfo->{libdir} ne '') {
462		push(@{$o->{libdirs}}, $lainfo->{libdir});
463	}
464	for my $e (qw(deplibs libdirs result)) {
465		if (@{$o->{$e}} > 50) {
466			$o->{$e} = reverse_zap_duplicates_ref($o->{$e});
467		}
468	}
469}
470
471sub internal_resolve_la
472{
473	my ($self, $o, $args, $level) = @_;
474	$level //= 0;
475	tsay {"resolve level: $level"};
476	$o->{pthread} = 0;
477	foreach my $_ (@$args) {
478		if ($_ eq '-pthread') {
479			$o->{pthread}++;
480			next;
481		}
482		push(@{$o->{result}}, $_);
483		next unless m/\.la$/;
484		require LT::LaFile;
485		my $lainfo = LT::LaFile->parse($_);
486		if  (!exists $lainfo->{cached}) {
487			$self->build_cache($lainfo, $level+1);
488		}
489		$o->{pthread} += $lainfo->{cached}{pthread};
490		for my $e (qw(deplibs libdirs result)) {
491			push(@{$o->{$e}}, @{$lainfo->{cached}{$e}});
492		}
493	}
494	$calls++;
495}
496
497END
498{
499	LT::Trace::print { "Calls to resolve_la: $calls\n" } if $calls;
500}
501
502# resolve .la files until a level with empty dependency_libs is reached.
503sub resolve_la
504{
505	my ($self, $deplibs, $libdirs) = @_;
506
507	tsay {"argvstring (pre resolve_la): @{$self->{args}}"};
508	my $o = { result => [], deplibs => $deplibs, libdirs => $libdirs};
509
510	$self->internal_resolve_la($o, $self->{args});
511	if ($o->{pthread}) {
512		unshift(@{$o->{result}}, '-pthread');
513		unshift(@{$o->{deplibs}}, '-pthread');
514	}
515
516	tsay {"argvstring (post resolve_la): @{$self->{args}}"};
517	$self->{args} = $o->{result};
518}
519
520# parse link flags and arguments
521# eliminate all -L and -l flags in the argument string and add the
522# corresponding directories and library names to the dirs/libs hashes.
523# fill deplibs, to be taken up as dependencies in the resulting .la file...
524# set up a hash for library files which haven't been found yet.
525# deplibs are formed by collecting the original -L/-l flags, plus
526# any .la files passed on the command line, EXCEPT when the .la file
527# does not point to a shared library.
528# pass 1
529# -Lfoo, -lfoo, foo.a, foo.la
530# recursively find .la files corresponding to -l flags; if there is no .la
531# file, just inspect the library file itself for any dependencies.
532sub internal_parse_linkargs1
533{
534	my ($self, $deplibs, $gp, $dirs, $libs, $args, $level) = @_;
535
536	$level //= 0;
537	tsay {"parse_linkargs1, level: $level"};
538	tsay {"  args: @$args"};
539	my $result   = $self->{result};
540
541	# first read all directories where we can search libraries
542	foreach my $_ (@$args) {
543		if (m/^-L(.*)/) {
544			if (!exists $dirs->{$1}) {
545				$dirs->{$1} = 1;
546				tsay {"    adding $_ to deplibs"}
547				    if $level == 0;
548				push @$deplibs, $_;
549			}
550		}
551	}
552	foreach my $_ (@$args) {
553		tsay {"  processing $_"};
554		if (!$_ || $_ eq '' || m/^\s+$/) {
555			# skip empty arguments
556		} elsif ($_ eq '-pthread') {
557			$self->{pthread} = 1;
558		} elsif (m/^-L(.*)/) {
559			# already read earlier, do nothing
560		} elsif (m/^-R(.*)/) {
561			# -R options originating from .la resolution
562			# those from @ARGV are in @Ropts
563			$gp->add_R($1);
564		} elsif (m/^-l(\S+)/) {
565			my @largs = ();
566			my $key = $1;
567			if (!exists $libs->{$key}) {
568				$libs->create($key);
569				require LT::LaFile;
570				my $lafile = LT::LaFile->find($key, $dirs);
571				if ($lafile) {
572					$libs->{$key}->{lafile} = $lafile;
573					my $absla = abs_path($lafile);
574					tsay {"    adding $absla to deplibs"}
575					    if $level == 0;
576					push @$deplibs, $absla;
577					push @$result, $lafile;
578					next;
579				} else {
580					$libs->{$key}->resolve_library($dirs, 1, 0, 'notyet', $gp);
581					my @deps = $libs->{$key}->inspect;
582					foreach my $d (@deps) {
583						my $k = basename($d);
584						$k =~ s/^(\S+)\.so.*$/$1/;
585						$k =~ s/^lib//;
586						push(@largs, "-l$k");
587					}
588				}
589			}
590			tsay {"    adding $_ to deplibs"} if $level == 0;
591			push @$deplibs, $_;
592			push(@$result, $_);
593			my $dummy = []; # no need to add deplibs recursively
594			$self->internal_parse_linkargs1($dummy, $gp, $dirs,
595			    $libs, \@largs, $level+1) if @largs;
596		} elsif (m/(\S+\/)*(\S+)\.a$/) {
597			(my $key = $2) =~ s/^lib//;
598			$dirs->{abs_dir($_)} = 1;
599			$libs->create($key)->{fullpath} = $_;
600			push(@$result, $_);
601		} elsif (m/(\S+\/)*(\S+)\.la$/) {
602			(my $key = $2) =~ s/^lib//;
603			$dirs->{abs_dir($_)} = 1;
604			my $fulla = abs_path($_);
605			require LT::LaFile;
606			my $lainfo = LT::LaFile->parse($fulla);
607			my $dlname = $lainfo->{dlname};
608			my $oldlib = $lainfo->{old_library};
609			my $libdir = $lainfo->{libdir};
610			if ($dlname ne '') {
611				if (!exists $libs->{$key}) {
612					$libs->create($key)->{lafile} = $fulla;
613				}
614			}
615			push(@$result, $_);
616			push(@$deplibs, $fulla) if $libdir ne '';
617		} elsif (m/(\S+\/)*(\S+)\.so(\.\d+){2}/) {
618			(my $key = $2) =~ s/^lib//;
619			$dirs->{abs_dir($_)} = 1;
620			$libs->create($key);
621			# not really normal argument
622			# -lfoo should be used instead, so convert it
623			push(@$result, "-l$key");
624		} else {
625			push(@$result, $_);
626		}
627	}
628}
629
630sub parse_linkargs1
631{
632	my ($self, $deplibs, $gp, $dirs, $libs, $args) = @_;
633	$self->{result} = [];
634	$self->internal_parse_linkargs1($deplibs, $gp, $dirs, $libs,
635	    $self->{args});
636    	push(@$deplibs, '-pthread') if $self->{pthread};
637	$self->{args} = $self->{result};
638}
639
640# pass 2
641# -Lfoo, -lfoo, foo.a
642# no recursion in pass 2
643# fill orderedlibs array, which is the sequence of shared libraries
644#   after resolving all .la
645# (this list may contain duplicates)
646# fill staticlibs array, which is the sequence of static and convenience
647#   libraries
648# XXX the variable $parser->{seen_la_shared} will register whether or not
649#     a .la file is found which refers to a shared library and which is not
650#     yet installed
651#     this is used to decide where to link executables and create wrappers
652sub parse_linkargs2
653{
654	my ($self, $gp, $orderedlibs, $staticlibs, $dirs, $libs) = @_;
655	tsay {"parse_linkargs2"};
656	tsay {"  args: @{$self->{args}}"};
657	my $result = [];
658
659	foreach my $_ (@{$self->{args}}) {
660		tsay {"  processing $_"};
661		if (!$_ || $_ eq '' || m/^\s+$/) {
662			# skip empty arguments
663		} elsif ($_ eq '-lc') {
664			# don't link explicitly with libc (just remove -lc)
665		} elsif ($_ eq '-pthread') {
666			$self->{pthread} = 1;
667		} elsif (m/^-L(.*)/) {
668			if (!exists $dirs->{$1}) {
669				$dirs->{$1} = 1;
670			}
671		} elsif (m/^-R(.*)/) {
672			# -R options originating from .la resolution
673			# those from @ARGV are in @Ropts
674			$gp->add_R($1);
675		} elsif (m/^-l(.*)/) {
676			my @largs = ();
677			my $key = $1;
678			$libs->create($key);
679			push @$orderedlibs, $key;
680		} elsif (m/(\S+\/)*(\S+)\.a$/) {
681			(my $key = $2) =~ s/^lib//;
682			$libs->create($key)->{fullpath} = $_;
683			push(@$staticlibs, $_);
684		} elsif (m/(\S+\/)*(\S+)\.la$/) {
685			(my $key = $2) =~ s/^lib//;
686			my $d = abs_dir($_);
687			$dirs->{$d} = 1;
688			my $fulla = abs_path($_);
689			require LT::LaFile;
690			my $lainfo = LT::LaFile->parse($fulla);
691			my $dlname = $lainfo->stringize('dlname');
692			my $oldlib = $lainfo->stringize('old_library');
693			my $installed = $lainfo->stringize('installed');
694			if ($dlname ne '' && $installed eq 'no') {
695				tsay {"seen uninstalled la shared in $_"};
696				$self->{seen_la_shared} = 1;
697			}
698			if ($dlname eq '' && -f "$d/$ltdir/$oldlib") {
699				push @$staticlibs, "$d/$ltdir/$oldlib";
700			} else {
701				if (!exists $libs->{$key}) {
702					$libs->create($key)->{lafile} = $fulla;
703				}
704				push @$orderedlibs, $key;
705			}
706		} elsif (m/^-Wl,(\S+)$/) {
707			# libtool accepts a list of -Wl options separated
708			# by commas, and possibly with a trailing comma
709			# which is not accepted by the linker
710			my @Wlflags = split(/,/, $1);
711			foreach my $f (@Wlflags) {
712				push(@$result, "-Wl,$f");
713			}
714		} else {
715			push(@$result, $_);
716		}
717	}
718	tsay {"end parse_linkargs2"};
719	return $result;
720}
721
722sub new
723{
724	my ($class, $args) = @_;
725	bless { args => $args, pthread => 0 }, $class;
726}
727
728package LT::Linker;
729use LT::Trace;
730use LT::Util;
731use File::Basename;
732use Cwd qw(abs_path);
733
734sub new
735{
736	my $class = shift;
737	bless {}, $class;
738}
739
740sub create_symlinks
741{
742	my ($self, $dir, $libs) = @_;
743	if (! -d $dir) {
744		mkdir($dir) or die "Cannot mkdir($dir) : $!\n";
745	}
746
747	foreach my $l (values %$libs) {
748		my $f = $l->{fullpath};
749		next if !defined $f;
750		next if $f =~ m/\.a$/;
751		my $libnames = [];
752		if (defined $l->{lafile}) {
753			require LT::LaFile;
754			my $lainfo = LT::LaFile->parse($l->{lafile});
755			my $librarynames = $lainfo->stringize('library_names');
756			@$libnames = split /\s/, $librarynames;
757			$libnames = reverse_zap_duplicates_ref($libnames);
758		} else {
759			push @$libnames, basename($f);
760		}
761		foreach my $libfile (@$libnames) {
762			my $link = "$dir/$libfile";
763			tsay {"ln -s $f $link"};
764			next if -f $link;
765			my $p = abs_path($f);
766			if (!symlink($p, $link)) {
767				die "Cannot create symlink($p, $link): $!\n"
768				    unless  $!{EEXIST};
769			}
770		}
771	}
772	return $dir;
773}
774
775sub common1
776{
777	my ($self, $parser, $gp, $deplibs, $libdirs, $dirs, $libs) = @_;
778
779	$parser->resolve_la($deplibs, $libdirs);
780	my $orderedlibs = [];
781	my $staticlibs = [];
782	my $args = $parser->parse_linkargs2($gp, $orderedlibs, $staticlibs, $dirs,
783	    $libs);
784	tsay {"staticlibs = \n", join("\n", @$staticlibs)};
785	tsay {"orderedlibs = @$orderedlibs"};
786	$orderedlibs = reverse_zap_duplicates_ref($orderedlibs);
787	tsay {"final orderedlibs = @$orderedlibs"};
788	return ($staticlibs, $orderedlibs, $args);
789}
790
791sub infer_libparameter
792{
793	my ($self, $a, $k) = @_;
794	my $lib = basename($a);
795	if ($lib =~ m/^lib(.*)\.so(\.\d+){2}$/) {
796		$lib = $1;
797	} elsif ($lib =~ m/^lib(.*)\.so$/) {
798		say "warning: library filename $a has no version number";
799		$lib = $1;
800	} else {
801		say "warning: cannot derive -l flag from library filename $a, assuming hash key -l$k";
802		$lib = $k;
803	}
804	return "-l$lib";
805}
806
8071;
808
809