aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Mares <mj@ucw.cz>2022-10-30 16:26:43 +0100
committerMartin Mares <mj@ucw.cz>2022-10-30 16:26:43 +0100
commitde53aa4fd7777a2602882bb7d4304e0b2ad6bc6f (patch)
tree57fb2a63be351b71bde8c4f73600adc3b99cee01
parent637ad022fcc53da9ef84d11f9772bcb02c0d02ea (diff)
parent59cb656889fe77f062b7391160188b70bf60c7b2 (diff)
downloadpciutils-de53aa4fd7777a2602882bb7d4304e0b2ad6bc6f.tar.gz
Merge remote-tracking branch 'pali/win32-dll'
-rw-r--r--Makefile72
-rw-r--r--lib/Makefile26
-rwxr-xr-xlib/configure20
-rw-r--r--lib/dllrsrc.rc.in35
-rw-r--r--lib/filter.c4
-rw-r--r--lib/internal.h17
-rw-r--r--lib/libpci.ver7
-rwxr-xr-xlib/ver2def.pl47
8 files changed, 200 insertions, 28 deletions
diff --git a/Makefile b/Makefile
index 9319bb4..e2e3bd7 100644
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,7 @@ HWDB=
# ABI version suffix in the name of the shared library
# (as we use proper symbol versioning, this seldom needs changing)
-ABI_VERSION=.3
+ABI_VERSION=3
# Installation directories
PREFIX=/usr/local
@@ -53,6 +53,8 @@ CC=cc
endif
AR=$(CROSS_COMPILE)ar
RANLIB=$(CROSS_COMPILE)ranlib
+DLLTOOL=$(CROSS_COMPILE)dlltool
+WINDRES=$(CROSS_COMPILE)windres
# Base name of the library (overridden on NetBSD, which has its own libpci)
LIBNAME=libpci
@@ -64,9 +66,9 @@ PCIINC_INS=lib/config.h lib/header.h lib/pci.h lib/types.h
export
-all: lib/$(PCILIB) lspci$(EXEEXT) setpci$(EXEEXT) example$(EXEEXT) lspci.8 setpci.8 pcilib.7 pci.ids.5 update-pciids update-pciids.8 $(PCI_IDS)
+all: lib/$(PCIIMPLIB) lspci$(EXEEXT) setpci$(EXEEXT) example$(EXEEXT) lspci.8 setpci.8 pcilib.7 pci.ids.5 update-pciids update-pciids.8 $(PCI_IDS)
-lib/$(PCILIB): $(PCIINC) force
+lib/$(PCIIMPLIB): $(PCIINC) force
$(MAKE) -C lib all
force:
@@ -80,8 +82,8 @@ PCIINC+=compat/getopt.h
COMMON+=compat/getopt.o
endif
-lspci$(EXEEXT): lspci.o ls-vpd.o ls-caps.o ls-caps-vendor.o ls-ecaps.o ls-kernel.o ls-tree.o ls-map.o $(COMMON) lib/$(PCILIB)
-setpci$(EXEEXT): setpci.o $(COMMON) lib/$(PCILIB)
+lspci$(EXEEXT): lspci.o ls-vpd.o ls-caps.o ls-caps-vendor.o ls-ecaps.o ls-kernel.o ls-tree.o ls-map.o $(COMMON) lib/$(PCIIMPLIB)
+setpci$(EXEEXT): setpci.o $(COMMON) lib/$(PCIIMPLIB)
LSPCIINC=lspci.h pciutils.h $(PCIINC)
lspci.o: lspci.c $(LSPCIINC)
@@ -100,11 +102,11 @@ lspci$(EXEEXT): LDLIBS+=$(LIBKMOD_LIBS)
ls-kernel.o: CFLAGS+=$(LIBKMOD_CFLAGS)
update-pciids: update-pciids.sh
- sed <$< >$@ "s@^DEST=.*@DEST=$(IDSDIR)/$(PCI_IDS)@;s@^PCI_COMPRESSED_IDS=.*@PCI_COMPRESSED_IDS=$(PCI_COMPRESSED_IDS)@"
+ sed <$< >$@ "s@^DEST=.*@DEST=$(if $(IDSDIR),$(IDSDIR)/,)$(PCI_IDS)@;s@^PCI_COMPRESSED_IDS=.*@PCI_COMPRESSED_IDS=$(PCI_COMPRESSED_IDS)@"
chmod +x $@
# The example of use of libpci
-example$(EXEEXT): example.o lib/$(PCILIB)
+example$(EXEEXT): example.o lib/$(PCIIMPLIB)
example.o: example.c $(PCIINC)
%$(EXEEXT): %.o
@@ -123,26 +125,30 @@ TAGS:
clean:
rm -f `find . -name "*~" -o -name "*.[oa]" -o -name "\#*\#" -o -name TAGS -o -name core -o -name "*.orig"`
- rm -f update-pciids lspci$(EXEEXT) setpci$(EXEEXT) example$(EXEEXT) lib/config.* *.[578] pci.ids.gz lib/*.pc lib/*.so lib/*.so.* tags
+ rm -f update-pciids lspci$(EXEEXT) setpci$(EXEEXT) example$(EXEEXT) lib/config.* *.[578] pci.ids.gz lib/*.pc lib/*.so lib/*.so.* lib/*.dll lib/*.def lib/dllrsrc.rc tags
rm -rf maint/dist
distclean: clean
install: all
# -c is ignored on Linux, but required on FreeBSD
- $(DIRINSTALL) -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(SBINDIR) $(DESTDIR)$(IDSDIR) $(DESTDIR)$(MANDIR)/man8 $(DESTDIR)$(MANDIR)/man7 $(DESTDIR)/$(MANDIR)/man5
+ $(DIRINSTALL) -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(SBINDIR) $(DESTDIR)$(IDSDIR) $(DESTDIR)$(MANDIR)/man8 $(DESTDIR)$(MANDIR)/man7 $(DESTDIR)$(MANDIR)/man5
$(INSTALL) -c -m 755 $(STRIP) lspci$(EXEEXT) $(DESTDIR)$(LSPCIDIR)
$(INSTALL) -c -m 755 $(STRIP) setpci$(EXEEXT) $(DESTDIR)$(SBINDIR)
$(INSTALL) -c -m 755 update-pciids $(DESTDIR)$(SBINDIR)
+ifneq ($(IDSDIR),)
$(INSTALL) -c -m 644 $(PCI_IDS) $(DESTDIR)$(IDSDIR)
+else
+ $(INSTALL) -c -m 644 $(PCI_IDS) $(DESTDIR)$(SBINDIR)
+endif
$(INSTALL) -c -m 644 lspci.8 setpci.8 update-pciids.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -c -m 644 pcilib.7 $(DESTDIR)$(MANDIR)/man7
$(INSTALL) -c -m 644 pci.ids.5 $(DESTDIR)$(MANDIR)/man5
ifeq ($(SHARED),yes)
ifeq ($(LIBEXT),dylib)
- ln -sf $(PCILIB) $(DESTDIR)$(LIBDIR)/$(LIBNAME)$(ABI_VERSION).$(LIBEXT)
-else
- ln -sf $(PCILIB) $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT)$(ABI_VERSION)
+ ln -sf $(PCILIB) $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(ABI_VERSION).$(LIBEXT)
+else ifeq ($(LIBEXT),so)
+ ln -sf $(PCILIB) $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT).$(ABI_VERSION)
endif
endif
@@ -152,37 +158,65 @@ endif
install-pcilib: lib/$(PCILIB)
$(DIRINSTALL) -m 755 $(DESTDIR)$(LIBDIR)
+ifeq ($(SHARED)_$(LIBEXT),yes_dll)
+# DLL library must have executable flag on disk and be placed in same directory as where are EXE files
+ $(DIRINSTALL) -m 755 $(DESTDIR)$(SBINDIR)
+ $(INSTALL) -c -m 755 lib/$(PCILIB) $(DESTDIR)$(SBINDIR)
+else
$(INSTALL) -c -m 644 lib/$(PCILIB) $(DESTDIR)$(LIBDIR)
+endif
install-lib: $(PCIINC_INS) install-pcilib
$(DIRINSTALL) -m 755 $(DESTDIR)$(INCDIR)/pci $(DESTDIR)$(PKGCFDIR)
$(INSTALL) -c -m 644 $(PCIINC_INS) $(DESTDIR)$(INCDIR)/pci
$(INSTALL) -c -m 644 lib/$(PCILIBPC) $(DESTDIR)$(PKGCFDIR)
+ifneq ($(PCIIMPLIB),$(PCILIB))
+ $(INSTALL) -c -m 644 lib/$(PCIIMPLIB) $(DESTDIR)$(LIBDIR)
+endif
+ifneq ($(PCIIMPDEF),)
+ $(INSTALL) -c -m 644 lib/$(PCIIMPDEF) $(DESTDIR)$(LIBDIR)
+endif
ifeq ($(SHARED),yes)
ifeq ($(LIBEXT),dylib)
- ln -sf $(PCILIB) $(DESTDIR)$(LIBDIR)/$(LIBNAME)$(ABI_VERSION).$(LIBEXT)
- ln -sf $(LIBNAME)$(ABI_VERSION).$(LIBEXT) $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT)
-else
- ln -sf $(PCILIB) $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT)$(ABI_VERSION)
- ln -sf $(LIBNAME).$(LIBEXT)$(ABI_VERSION) $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT)
+ ln -sf $(PCILIB) $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(ABI_VERSION).$(LIBEXT)
+ ln -sf $(LIBNAME).$(ABI_VERSION).$(LIBEXT) $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT)
+else ifeq ($(LIBEXT),so)
+ ln -sf $(PCILIB) $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT).$(ABI_VERSION)
+ ln -sf $(LIBNAME).$(LIBEXT).$(ABI_VERSION) $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT)
endif
endif
uninstall: all
rm -f $(DESTDIR)$(SBINDIR)/lspci$(EXEEXT) $(DESTDIR)$(SBINDIR)/setpci$(EXEEXT) $(DESTDIR)$(SBINDIR)/update-pciids
+ifneq ($(IDSDIR),)
rm -f $(DESTDIR)$(IDSDIR)/$(PCI_IDS)
+else
+ rm -f $(DESTDIR)$(SBINDIR)/$(PCI_IDS)
+endif
rm -f $(DESTDIR)$(MANDIR)/man8/lspci.8 $(DESTDIR)$(MANDIR)/man8/setpci.8 $(DESTDIR)$(MANDIR)/man8/update-pciids.8
rm -f $(DESTDIR)$(MANDIR)/man7/pcilib.7
rm -f $(DESTDIR)$(MANDIR)/man5/pci.ids.5
+ifeq ($(SHARED)_$(LIBEXT),yes_dll)
+ rm -f $(DESTDIR)$(SBINDIR)/$(PCILIB)
+else
rm -f $(DESTDIR)$(LIBDIR)/$(PCILIB)
+endif
rm -f $(DESTDIR)$(PKGCFDIR)/$(PCILIBPC)
rm -f $(addprefix $(DESTDIR)$(INCDIR)/pci/,$(notdir $(PCIINC_INS)))
+ifneq ($(PCIIMPLIB),$(PCILIB))
+ rm -f $(DESTDIR)$(LIBDIR)/$(PCIIMPLIB)
+endif
+ifneq ($(PCIIMPDEF),)
+ rm -f $(DESTDIR)$(LIBDIR)/$(PCIIMPDEF)
+endif
ifeq ($(SHARED),yes)
+ifneq ($(LIBEXT),dll)
rm -f $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT)
ifeq ($(LIBEXT),dylib)
- rm -f $(DESTDIR)$(LIBDIR)/$(LIBNAME)$(ABI_VERSION).$(LIBEXT)
+ rm -f $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(ABI_VERSION).$(LIBEXT)
else
- rm -f $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT)$(ABI_VERSION)
+ rm -f $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT).$(ABI_VERSION)
+endif
endif
endif
diff --git a/lib/Makefile b/lib/Makefile
index 400c32d..13c2a19 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -71,13 +71,29 @@ $(PCILIB): $(addsuffix .o,$(OBJS))
$(AR) rcs $@ $^
$(RANLIB) $@
else
+ifeq ($(LIBEXT),dll)
+all: $(PCIIMPDEF) $(PCIIMPLIB)
+build.def: $(PCIIMPDEF)
+$(PCIIMPDEF): libpci.ver ver2def.pl
+ perl ver2def.pl libpci.ver $(PCILIB) build.def $(PCIIMPDEF)
+$(PCIIMPLIB): $(PCIIMPDEF)
+ $(DLLTOOL) --input-def $< --output-lib $@
+comma := ,
+dllrsrc.rc: dllrsrc.rc.in
+ sed <$< >$@ -e 's,@PCILIB_VERSION@,$(PCILIB_VERSION),' \
+ -e 's,@PCILIB_VERSION_WINRC@,$(subst .,\$(comma),$(PCILIB_VERSION).0),' \
+ -e 's,@PCILIB@,$(PCILIB),' \
+ -e 's,@DEBUG_BUILD@,$(if $(findstring -g,$(CFLAGS)),1,0),'
+dllrsrc.o: dllrsrc.rc
+ $(WINDRES) --input=$< --output=$@ --input-format=rc --output-format=coff
+OBJS += dllrsrc
+endif
CFLAGS += -fPIC -fvisibility=hidden
$(PCILIB): $(addsuffix .o,$(OBJS))
- ifdef PCI_HAVE_PM_DARWIN_DEVICE
- $(CC) -shared $(LDFLAGS) $(SONAME) -Wl,-install_name,$(LIBDIR)/$(PCILIB) -o $@ $^ $(LIB_LDLIBS)
- else
- $(CC) -shared $(LDFLAGS) $(SONAME) -Wl,--version-script=libpci.ver -o $@ $^ $(LIB_LDLIBS)
- endif
+ $(CC) -shared $(CFLAGS) $(LDFLAGS) $(PCILIB_LDFLAGS) -o $@ $^ $(LIB_LDLIBS)
+ifeq ($(LIBEXT),dll)
+$(PCILIB): build.def
+endif
endif
$(PCILIBPC): libpci.pc.in
diff --git a/lib/configure b/lib/configure
index 7585bfe..f5c2c0d 100755
--- a/lib/configure
+++ b/lib/configure
@@ -166,6 +166,7 @@ case $sys in
fi
;; esac
EXEEXT=.exe
+ LIBEXT=dll
;;
beos|haiku)
case $cpu in
@@ -291,6 +292,8 @@ if [ "$SHARED" = no ] ; then
else
if [ "$LIBEXT" = so ]; then
echo >>$m 'PCILIB=$(LIBNAME).$(LIBEXT).$(VERSION)'
+ elif [ "$LIBEXT" = dll ]; then
+ echo >>$m 'PCILIB=$(LIBNAME)$(ABI_VERSION).$(LIBEXT)'
else
echo >>$m 'PCILIB=$(LIBNAME).$(VERSION).$(LIBEXT)'
fi
@@ -298,11 +301,24 @@ else
echo >>$m 'LDLIBS='
echo >>$m 'LIB_LDLIBS=$(WITH_LIBS)'
echo >>$c '#define PCI_SHARED_LIB'
- if [ "$SHARED" = yes -a "$LIBEXT" = so ]; then
- echo >>$m 'SONAME=-Wl,-soname,$(LIBNAME).$(LIBEXT)$(ABI_VERSION)'
+ if [ "$LIBEXT" = so ]; then
+ echo >>$m 'PCILIB_LDFLAGS+=-Wl,-soname,$(LIBNAME).$(LIBEXT).$(ABI_VERSION)'
+ echo >>$m 'PCILIB_LDFLAGS+=-Wl,--version-script=libpci.ver'
+ elif [ "$LIBEXT" = dylib ]; then
+ echo >>$m 'PCILIB_LDFLAGS+=-Wl,-install_name,$(LIBDIR)/$(PCILIB)'
+ elif [ "$LIBEXT" = dll ]; then
+ echo >>$m 'PCIIMPDEF=$(LIBNAME)$(ABI_VERSION).def'
+ # GCC's -fvisibility=hidden is broken for Windows targets, use -Wl,--exclude-all-symbols instead (supported since GNU LD 2.21)
+ echo >>$m 'PCILIB_LDFLAGS+=-Wl,--exclude-all-symbols'
fi
fi
echo >>$m 'PCILIBPC=$(LIBNAME).pc'
+if [ "$SHARED" != no ] && [ "$LIBEXT" = dll ]; then
+ echo >>$m 'PCIIMPLIB=$(PCILIB).a'
+else
+ echo >>$m 'PCIIMPLIB=$(PCILIB)'
+fi
+
echo >>$c "#define PCILIB_VERSION \"$VERSION\""
sed '/"/{s/^#define \([^ ]*\) "\(.*\)"$/\1=\2/;p;d;};s/^#define \(.*\)/\1=1/' <$c >>$m
diff --git a/lib/dllrsrc.rc.in b/lib/dllrsrc.rc.in
new file mode 100644
index 0000000..519772b
--- /dev/null
+++ b/lib/dllrsrc.rc.in
@@ -0,0 +1,35 @@
+#include <windows.h>
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION @PCILIB_VERSION_WINRC@
+PRODUCTVERSION @PCILIB_VERSION_WINRC@
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#if @DEBUG_BUILD@
+FILEFLAGS VS_FF_DEBUG
+#else
+FILEFLAGS 0
+#endif
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE 0
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ /*
+ * GNU windres seems that converts 7-bit ASCII strings to UTF-16,
+ * so specify UNICODE/UTF-16 encoding (0x04B0) for these strings.
+ */
+ BLOCK "040904B0" /* Default U.S. English language, UNICODE/UTF-16 codepage */
+ BEGIN
+ VALUE "FileDescription", "libpci"
+ VALUE "FileVersion", "@PCILIB_VERSION@"
+ VALUE "InternalName", "@PCILIB@"
+ VALUE "OriginalFilename", "@PCILIB@"
+ VALUE "ProductName", "pciutils"
+ VALUE "ProductVersion", "@PCILIB_VERSION@"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 0x004B0 /* Default U.S. English language, UNICODE/UTF-16 codepage */
+ END
+END
diff --git a/lib/filter.c b/lib/filter.c
index d025a96..7038451 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -204,13 +204,13 @@ pci_filter_match_v38(struct pci_filter *f, struct pci_dev *d)
}
if (f->device_class >= 0)
{
- pci_fill_info(d, PCI_FILL_CLASS);
+ pci_fill_info_v38(d, PCI_FILL_CLASS);
if ((f->device_class ^ d->device_class) & f->device_class_mask)
return 0;
}
if (f->prog_if >= 0)
{
- pci_fill_info(d, PCI_FILL_CLASS_EXT);
+ pci_fill_info_v38(d, PCI_FILL_CLASS_EXT);
if (f->prog_if != d->prog_if)
return 0;
}
diff --git a/lib/internal.h b/lib/internal.h
index 0a5dce4..11cf5a6 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -21,8 +21,15 @@
#else
#define STATIC_ALIAS(_decl, _for)
#define DEFINE_ALIAS(_decl, _for) extern _decl __attribute__((alias(#_for)))
+#ifdef _WIN32
+/* GCC does not support asm .symver directive for Windows targets, so define new external global function symbol as alias to internal symbol */
+#define SYMBOL_VERSION(_int, _ext) asm(".globl\t" PCI_STRINGIFY(__MINGW_USYMBOL(_ext)) "\n\t" \
+ ".def\t" PCI_STRINGIFY(__MINGW_USYMBOL(_ext)) ";\t.scl\t2;\t.type\t32;\t.endef\n\t" \
+ ".set\t" PCI_STRINGIFY(__MINGW_USYMBOL(_ext)) "," PCI_STRINGIFY(__MINGW_USYMBOL(_int)))
+#else
#define SYMBOL_VERSION(_int, _ext) asm(".symver " #_int "," #_ext)
#endif
+#endif
#else
#define VERSIONED_ABI
#define STATIC_ALIAS(_decl, _for) _decl { return _for; }
@@ -33,6 +40,16 @@
#include "pci.h"
#include "sysdep.h"
+/* Old 32-bit-only versions of MinGW32 do not define __MINGW_USYMBOL macro */
+#ifdef __MINGW32__
+#ifndef __MINGW_USYMBOL
+#define __MINGW_USYMBOL(sym) _##sym
+#endif
+#endif
+
+#define _PCI_STRINGIFY(x) #x
+#define PCI_STRINGIFY(x) _PCI_STRINGIFY(x)
+
struct pci_methods {
char *name;
char *help;
diff --git a/lib/libpci.ver b/lib/libpci.ver
index bd5ae23..33ee024 100644
--- a/lib/libpci.ver
+++ b/lib/libpci.ver
@@ -4,6 +4,13 @@
* Visibility declarations in the source take precedence over this script,
* so we can boldly declare pci_* as public and still keep the internal
* functions properly hidden.
+ *
+ * To preserve compatibility of Windows DLL file, always add new symbol at
+ * the end of file and never change order of symbols nor version sections.
+ * On Windows the last referenced version of the symbol is the default one.
+
+ * For PE/COFF targets this file is processed by ver2def.pl script and not
+ * by GNU LD linker like for ELF targets.
*/
LIBPCI_3.0 {
diff --git a/lib/ver2def.pl b/lib/ver2def.pl
new file mode 100755
index 0000000..18231bc
--- /dev/null
+++ b/lib/ver2def.pl
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+die "Usage: $0 script.ver dllname build.def import.def\n" if @ARGV != 4;
+my ($verfile, $dllname, $builddef, $importdef) = @ARGV;
+open my $verfh, '<', $verfile or die "Cannot open input file $verfile: $!\n";
+my $input = join '', <$verfh>;
+close $verfh;
+my @syms;
+my (%cnt, %last, %ords);
+$input =~ s/\/\*.*?\*\///sg; # Remove C comments
+while ($input =~ m/(\S+)\s*\{((?:[^\{\}]|\{(?2)\})+)\}\s*;/sg) { # Split {...}
+ my ($ver, $block) = ($1, $2);
+ while ($block =~ s/(\S+)\s*:((?:[^\{\}:]|\{(?2)\})+)$//sg) { # Split section:
+ my ($section, $syms) = ($1, $2);
+ next if $section ne 'global';
+ $syms =~ s/\s+//g;
+ foreach (split /;\s*/, $syms) { # Split symbols
+ $cnt{$_}++;
+ $last{$_} = $ver;
+ push @syms, [$_, $ver];
+ }
+ }
+}
+open my $importfh, '>', $importdef or die "Cannot open output file $importdef: $!\n";
+open my $buildfh, '>', $builddef or die "Cannot open output file $builddef: $!\n";
+print $importfh "LIBRARY \"$dllname\"\n";
+print $importfh "EXPORTS\n";
+print $buildfh "EXPORTS\n";
+my $ord = 1;
+foreach (@syms) {
+ my ($sym, $ver) = @{$_};
+ print $importfh "\"$sym\@$ver\" \@$ord\n";
+ if ($last{$sym} ne $ver) {
+ print $buildfh "\"$sym\@$ver\" \@$ord\n";
+ } else {
+ $ords{$sym} = $ord;
+ print $buildfh "\"$sym\@$ver\" = " . (($cnt{$sym} > 1) ? "\"$sym\@\@$ver\"" : $sym) . " \@$ord\n"
+ }
+ $ord++;
+}
+# GNU dlltool has broken calculation of ordinals for aliased symbols, so specify ordinals explicitly
+# GNU LD prior 2.21 has broken handling of symbols with dot character
+# Operator == for defining symbol alias is supported since GNU dlltool 2.21
+print $importfh "$_ \@$ords{$_} == \"$_\@$last{$_}\"\n" foreach sort keys %last;
+close $importfh;
+close $buildfh;