[pkg-golang-devel] go shared library packaging changes

Michael Hudson-Doyle michael.hudson at canonical.com
Mon Feb 1 03:48:56 UTC 2016


Hi,

As you probably all know, I've been working on Go shared libraries for
a while now and it's time to start actually using these things in
Debian and Ubuntu. Ubuntu has deadlines Debian doesn't, so this work
will probably happen in Ubuntu first, but I'd like to make sure that
I'm heading in an overall direction that's acceptable to Debian.

I'm attaching two patches, one for golang that builds the Go standard
library into a shared libraray and one for dh-golang that enables
packages to link against that (and any other packages that have had
their packaging updated to build a shared library). I've written a bad
perl script (http://paste.ubuntu.com/14675422/) that converts a
package to building a shared library package.

So, um, thoughts? Would these patches be OK for Debian after 1.6 is uploaded?

Cheers,
mwh
-------------- next part --------------
diff -Nru golang-1.6~rc1/debian/changelog golang-1.6~rc1/debian/changelog
--- golang-1.6~rc1/debian/changelog	2016-01-29 10:22:53.000000000 +1300
+++ golang-1.6~rc1/debian/changelog	2016-02-01 16:31:05.000000000 +1300
@@ -1,3 +1,10 @@
+golang (2:1.6~rc1-0ubuntu2) xenial; urgency=medium
+
+  * Build the Go standard library into a shared library on most architectures.
+    (LP: #1508122)
+
+ -- Michael Hudson-Doyle <michael.hudson at canonical.com>  Mon, 01 Feb 2016 15:17:05 +1300
+
 golang (2:1.6~rc1-0ubuntu1) xenial; urgency=medium
 
   * New upstream version.
diff -Nru golang-1.6~rc1/debian/control golang-1.6~rc1/debian/control
--- golang-1.6~rc1/debian/control	2016-01-18 07:24:14.000000000 +1300
+++ golang-1.6~rc1/debian/control	2016-02-01 15:16:05.000000000 +1300
@@ -131,3 +131,20 @@
  .
  This package is a metapackage that, when installed, guarantees
  that (most of) a full Go development environment is installed.
+
+Package: libgolang-std1
+Architecture: amd64 arm64 armhf i386 ppc64el
+Pre-Depends: ${misc:Pre-Depends}
+Provides: ${golang:Provides}
+Depends: ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends}
+Description: Go standard shared library
+
+Package: golang-go-shared-dev
+Architecture: amd64 arm64 armhf i386 ppc64el
+Pre-Depends: ${misc:Pre-Depends}
+Depends: golang-go (= ${binary:Version}),
+         libgolang-std1 (= ${binary:Version}),
+         ${misc:Depends},
+         ${perl:Depends},
+         ${shlibs:Depends}
+Description: Go standard shared library support files
diff -Nru golang-1.6~rc1/debian/helpers/installshlib.sh golang-1.6~rc1/debian/helpers/installshlib.sh
--- golang-1.6~rc1/debian/helpers/installshlib.sh	1970-01-01 12:00:00.000000000 +1200
+++ golang-1.6~rc1/debian/helpers/installshlib.sh	2016-02-01 16:06:32.000000000 +1300
@@ -0,0 +1,17 @@
+#!/bin/bash
+set -eux
+GOARCH=$(./bin/go env GOARCH)
+
+./bin/go build -o ./bin/readabihash -linkshared -ldflags="-r ''" debian/helpers/readabihash.go
+
+TRIPLET=$(dpkg-architecture -qDEB_HOST_MULTIARCH)
+
+mkdir -p debian/libgolang-std1/usr/lib/${TRIPLET}
+mv pkg/linux_${GOARCH}_dynlink/libstd.so debian/libgolang-std1/usr/lib/${TRIPLET}/libgolang-std.so.1
+
+ln -s ../../../${TRIPLET}/libgolang-std.so.1 pkg/linux_${GOARCH}_dynlink/libstd.so
+
+mkdir -p debian/golang-go-shared-dev/usr/lib/go/pkg/
+mv pkg/linux_${GOARCH}_dynlink/ debian/golang-go-shared-dev/usr/lib/go/pkg/
+
+cp bin/readabihash debian/golang-go-shared-dev/usr/lib/go/pkg/
diff -Nru golang-1.6~rc1/debian/helpers/readabihash.go golang-1.6~rc1/debian/helpers/readabihash.go
--- golang-1.6~rc1/debian/helpers/readabihash.go	1970-01-01 12:00:00.000000000 +1200
+++ golang-1.6~rc1/debian/helpers/readabihash.go	2016-02-01 15:16:05.000000000 +1300
@@ -0,0 +1,85 @@
+package main
+
+import (
+	"debug/elf"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"log"
+	"os"
+)
+
+func rnd(v int32, r int32) int32 {
+	if r <= 0 {
+		return v
+	}
+	v += r - 1
+	c := v % r
+	if c < 0 {
+		c += r
+	}
+	v -= c
+	return v
+}
+
+func readwithpad(r io.Reader, sz int32) ([]byte, error) {
+	full := rnd(sz, 4)
+	data := make([]byte, full)
+	_, err := r.Read(data)
+	if err != nil {
+		return nil, err
+	}
+	data = data[:sz]
+	return data, nil
+}
+
+func readnote(filename, name string, type_ int32) ([]byte, error) {
+	f, err := elf.Open(filename)
+	if err != nil {
+		return nil, err
+	}
+	for _, sect := range f.Sections {
+		if sect.Type != elf.SHT_NOTE {
+			continue
+		}
+		r := sect.Open()
+		for {
+			var namesize, descsize, nt_type int32
+			err = binary.Read(r, f.ByteOrder, &namesize)
+			if err != nil {
+				if err == io.EOF {
+					break
+				}
+				return nil, fmt.Errorf("read namesize failed", err)
+			}
+			err = binary.Read(r, f.ByteOrder, &descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read descsize failed", err)
+			}
+			err = binary.Read(r, f.ByteOrder, &nt_type)
+			if err != nil {
+				return nil, fmt.Errorf("read type failed", err)
+			}
+			nt_name, err := readwithpad(r, namesize)
+			if err != nil {
+				return nil, fmt.Errorf("read name failed", err)
+			}
+			desc, err := readwithpad(r, descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read desc failed", err)
+			}
+			if name == string(nt_name) && type_ == nt_type {
+				return desc, nil
+			}
+		}
+	}
+	return nil, nil
+}
+
+func main() {
+	desc, err := readnote(os.Args[1], "Go\x00\x00", 2)
+	if err != nil {
+		log.Fatalf("readnote failed: %v", err)
+	}
+	fmt.Printf("%x\n", desc)
+}
diff -Nru golang-1.6~rc1/debian/libgolang-std1.lintian-overrides golang-1.6~rc1/debian/libgolang-std1.lintian-overrides
--- golang-1.6~rc1/debian/libgolang-std1.lintian-overrides	1970-01-01 12:00:00.000000000 +1200
+++ golang-1.6~rc1/debian/libgolang-std1.lintian-overrides	2016-02-01 15:16:05.000000000 +1300
@@ -0,0 +1,3 @@
+# Go shared libraries are not linked by the system linker so
+# the .so symlinks are not where lintian expects.
+libgolang-std1: dev-pkg-without-shlib-symlink
diff -Nru golang-1.6~rc1/debian/rules golang-1.6~rc1/debian/rules
--- golang-1.6~rc1/debian/rules	2016-01-18 07:24:50.000000000 +1300
+++ golang-1.6~rc1/debian/rules	2016-02-01 15:36:55.000000000 +1300
@@ -19,6 +19,14 @@
 	RUN_TESTS := false
 endif
 
+shlib_archs = amd64 arm64 armhf i386 ppc64el
+IS_SHLIB_ARCH := false
+ifneq (,$(filter $(DEB_HOST_ARCH),$(shlib_archs)))
+	IS_SHLIB_ARCH := true
+endif
+
+multiarch := $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
+
 %:
 	+dh --parallel $(opt_no_act) $@
 
@@ -55,6 +63,11 @@
 
 override_dh_install-arch:
 ifeq (true, $(IS_GOLANG_ARCH))
+ifeq (true, $(IS_SHLIB_ARCH))
+	set -ex; \
+		export PATH="$(GOROOT)/bin:$$PATH"; \
+		$(CURDIR)/debian/helpers/installshlib.sh
+endif
 	dh_install --fail-missing
 	# Remove .syso files of the race detector; they are binary files that
 	# are not built from source in the go source distribution.
@@ -71,6 +84,8 @@
 override_dh_strip:
 	# strip disabled as golang upstream doesn't support it and it makes go
 	# crash. See http://bugs.debian.org/717172
+	strip --strip-unneeded $(CURDIR)/debian/libgolang-std1/usr/lib/$(multiarch)/libgolang-std.so.1
+	strip --strip-unneeded $(CURDIR)/debian/golang-go-shared-dev/usr/lib/go/pkg/readabihash
 
 override_dh_installdeb:
 	dh_installdeb
@@ -86,6 +101,13 @@
 override_dh_shlibdeps:
 	dh_shlibdeps -Xtestdata -Xtest
 
+override_dh_makeshlibs:
+	LDIR=$(CURDIR)/debian/libgolang-std1/usr/lib/$(multiarch); \
+	HASH=$$(LD_LIBRARY_PATH=$$LDIR:$$LD_LIBRARY_PATH $(CURDIR)/bin/readabihash $$LDIR/libgolang-std.so.1); \
+	dh_makeshlibs -Vlibgolang-std1-$$HASH; \
+		echo "golang:Provides=libgolang-std1-$$HASH" >> $(CURDIR)/debian/libgolang-std1.substvars
+
+
 override_dh_auto_build-arch:
 ifeq (true, $(IS_GOLANG_ARCH))
 	[ -f VERSION ] || echo "debian snapshot +$$(dpkg-parsechangelog -SVersion)" > VERSION
@@ -93,6 +115,11 @@
 		&& cd src \
 		&& $(CURDIR)/debian/helpers/goenv.sh \
 			bash ./make.bash --no-banner
+ifeq (true, $(IS_SHLIB_ARCH))
+	$(CURDIR)/bin/go install -v -buildmode=shared \
+		-ldflags '-extldflags "-Wl,-soname=libgolang-std.so.1"' \
+		std
+endif
 endif
 
 opt_no_act :=
-------------- next part --------------
diff -Nru dh-golang-1.12/debian/changelog dh-golang-1.12ubuntu1/debian/changelog
--- dh-golang-1.12/debian/changelog	2015-08-11 05:46:19.000000000 +1200
+++ dh-golang-1.12ubuntu1/debian/changelog	2015-12-16 17:43:45.000000000 +1300
@@ -1,3 +1,9 @@
+dh-golang (1.12ubuntu1) xenial; urgency=medium
+
+  * Shared library support.
+
+ -- Michael Hudson-Doyle <michael.hudson at canonical.com>  Wed, 16 Dec 2015 17:43:31 +1300
+
 dh-golang (1.12) unstable; urgency=medium
 
   [ Hilko Bengen ]
diff -Nru dh-golang-1.12/example/control-dev dh-golang-1.12ubuntu1/example/control-dev
--- dh-golang-1.12/example/control-dev	1970-01-01 12:00:00.000000000 +1200
+++ dh-golang-1.12ubuntu1/example/control-dev	2015-04-11 03:42:44.000000000 +1200
@@ -0,0 +1,14 @@
+Source: golang-go-library
+Section: net
+Priority: extra
+Maintainer: Go Packager <go-pkg at example.com>
+Build-Depends: debhelper (>= 8.0.0), dh-golang, golang-go
+Standards-Version: 3.9.2
+#Vcs-Git: git://git.debian.org/collab-maint/dcs.git
+#Vcs-Browser: http://git.debian.org/?p=collab-maint/dcs.git;a=summary
+
+Package: golang-go-library-dev
+Architecture: all
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Random Go library
+ A random Go library that does something very useful.
diff -Nru dh-golang-1.12/example/control-dev-shared dh-golang-1.12ubuntu1/example/control-dev-shared
--- dh-golang-1.12/example/control-dev-shared	1970-01-01 12:00:00.000000000 +1200
+++ dh-golang-1.12ubuntu1/example/control-dev-shared	2015-04-11 03:42:44.000000000 +1200
@@ -0,0 +1,21 @@
+Source: golang-go-library
+Section: net
+Priority: extra
+Maintainer: Go Packager <go-pkg at example.com>
+Build-Depends: debhelper (>= 8.0.0), dh-golang, golang-go, golang-go-shared-dev
+Standards-Version: 3.9.2
+#Vcs-Git: git://git.debian.org/collab-maint/dcs.git
+#Vcs-Browser: http://git.debian.org/?p=collab-maint/dcs.git;a=summary
+
+Package: golang-go-library-dev
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, libgo-library1 (= ${binary:Version})
+Description: Random Go library -- development files
+ A random Go library that does something very useful.
+
+Package: libgo-library1
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Provides: ${golang:Provides}
+Description: Random Go library -- shared library
+ A random Go library that does something very useful.
diff -Nru dh-golang-1.12/lib/Debian/Debhelper/Buildsystem/golang.pm dh-golang-1.12ubuntu1/lib/Debian/Debhelper/Buildsystem/golang.pm
--- dh-golang-1.12/lib/Debian/Debhelper/Buildsystem/golang.pm	2015-08-07 19:46:59.000000000 +1200
+++ dh-golang-1.12ubuntu1/lib/Debian/Debhelper/Buildsystem/golang.pm	2015-12-18 16:06:14.000000000 +1300
@@ -2,6 +2,7 @@
 
 use strict;
 use base 'Debian::Debhelper::Buildsystem';
+use Data::Dumper;
 use Debian::Debhelper::Dh_Lib; 
 use Dpkg::Control::Info;
 use File::Copy; # in core since 5.002
@@ -21,6 +22,7 @@
     my $this = $class->SUPER::new(@_);
     $this->prefer_out_of_source_building();
     _set_dh_gopkg();
+    $this->read_shlibconfig();
     return $this;
 }
 
@@ -35,6 +37,50 @@
     $ENV{DH_GOPKG} = $source->{"XS-Go-Import-Path"};
 }
 
+sub read_shlibconfig {
+    my $this = shift;
+    my $config = {linkshared => !!$ENV{DH_GOLANG_LINK_SHARED}};
+
+    my $control = Dpkg::Control::Info->new();
+
+    printf("heeelooo\n");
+
+    foreach my $pkg (@{$control->{packages}}) {
+        printf("+ %s\n", $pkg->{Package});
+        if ($pkg->{Package} =~ /^lib(golang.*?)-?([0-9]+)$/) {
+            $config->{libpkg} = $pkg->{Package};
+            $config->{libname} = $1;
+            $config->{sover} = $2;
+            $config->{linkshared} = 1;
+        } elsif ($pkg->{Package} =~ /-dev$/ && !$config->{devpkg}) {
+            $config->{devpkg} = $pkg->{Package};
+        }
+    }
+
+    print Dumper($config);
+    
+    # XXX Could do some consistency checks here e.g
+    # 1) make sure there is a devpkg if there is a libpkg
+    # 2) make sure devpkg depends on libpkg
+    # 3) make sure libpkg has "Provides: ${golang:Provides}"
+    # Maybe this is more in the realm of lintian.
+
+    $config->{soname} = sprintf("lib%s.so.%s", $config->{libname}, $config->{sover});
+
+    $this->{shlibconfig} = $config;
+}
+
+
+sub set_GOPATH {
+    my $this = shift;
+
+    if ($this->{shlibconfig}->{linkshared}) {
+        $ENV{GOPATH} = $this->{cwd} . '/' . $this->get_builddir() . ':' . $this->{cwd} . '/' . $this->get_builddir() . '/shlibdeps' . ':' . $this->{cwd} . '/' . $this->get_builddir() . '/srcdeps';
+    } else {
+        $ENV{GOPATH} = $this->{cwd} . '/' . $this->get_builddir()
+    }
+}
+
 sub _link_contents {
     my ($src, $dst) = @_;
 
@@ -123,26 +169,50 @@
     # buildroot.
     ############################################################################
 
-    # NB: The naïve idea of just setting GOPATH=$builddir:/usr/share/godoc does
-    # not work. Let’s call the two paths in $GOPATH components. go(1), when
-    # installing a package, such as github.com/Debian/dcs/cmd/..., will also
-    # install the compiled dependencies, e.g. github.com/mstap/godebiancontrol.
-    # When such a dependency is found in a component’s src/ directory, the
-    # resulting files will be stored in the same component’s pkg/ directory.
-    # That is, in this example, go(1) wants to modify
-    # /usr/share/gocode/pkg/linux_amd64/github.com/mstap/godebiancontrol, which
-    # will obviously not succeed due to permission errors.
-    #
-    # Therefore, we just work with a single component that is under our control
-    # and symlink all the sources into that component ($builddir).
-
-    _link_contents('/usr/share/gocode/src', "$builddir/src");
+    if ($this->{shlibconfig}->{linkshared}) {
+        # When building or linking against shared libraries, we must make available any
+        # shared libraries that are already on the system. GOPATH is set up to have three
+        # components: $builddir (for the package we are building), $builddir/shlibdeps
+        # (for packages that are built into shared libraries that have already been
+        # installed) and $builddir/srcdeps (for dependencies that have only been installed
+        # as source). The shlibdeps component is deliberately set up so that the build
+        # can't write to it.
+        my $installed_shlib_data_dir = "/usr/lib/" . dpkg_architecture_value("DEB_HOST_MULTIARCH") . "/gocode";
+        if (-d $installed_shlib_data_dir) {
+            make_path("$builddir/shlibdeps/pkg");
+            # XXX Why can't we just symlink builddir/shlibdeps to $installed_shlib_data_dir?
+            # I forget, but there must be some reason which I should try and explain... (I
+            # think maybe putting symlinks on GOPATH doesn't work?)
+            $this->doit_in_builddir("ln", "-sT", "$installed_shlib_data_dir/src", "shlibdeps/src");
+            complex_doit("ln", "-s", "$installed_shlib_data_dir/pkg/*_dynlink", "$builddir/shlibdeps/pkg");
+        }
+        make_path("$builddir/srcdeps/src");
+        _link_contents('/usr/share/gocode/src', "$builddir/srcdeps/src");
+    } else {
+        # NB: The naïve idea of just setting GOPATH=$builddir:/usr/share/gocode does
+        # not work. Let’s call the two paths in $GOPATH components. go(1), when
+        # installing a package, such as github.com/Debian/dcs/cmd/..., will also
+        # install the compiled dependencies, e.g. github.com/mstap/godebiancontrol.
+        # When such a dependency is found in a component’s src/ directory, the
+        # resulting files will be stored in the same component’s pkg/ directory.
+        # That is, in this example, go(1) wants to modify
+        # /usr/share/gocode/pkg/linux_amd64/github.com/mstap/godebiancontrol, which
+        # will obviously not succeed due to permission errors.
+        #
+        # Therefore, we just work with a single component that is under our control
+        # and symlink all the sources into that component ($builddir).
+        _link_contents('/usr/share/gocode/src', "$builddir/src");
+    }
 }
 
 sub get_targets {
     my $buildpkg = $ENV{DH_GOLANG_BUILDPKG} || "$ENV{DH_GOPKG}/...";
-    my $output = qx(go list $buildpkg);
     my @excludes = split(/ /, $ENV{DH_GOLANG_EXCLUDES});
+    # XXX Why do this?
+    if (!@excludes) {
+        return ($buildpkg)
+    }
+    my $output = qx(go list $buildpkg);
     my @targets = split(/\n/, $output);
 
     # Remove all targets that are matched by one of the regular expressions in DH_GOLANG_EXCLUDES.
@@ -153,20 +223,73 @@
     return @targets;
 }
 
+sub buildX {
+    if ($dh{VERBOSE}) {
+        return ("-x");
+    } else {
+        return ();
+    }
+}
+
+# Return where the go tool thinks the shlib for our targets is.
+sub go_shlib_path {
+    my @targets = get_targets();
+    # other things will blow up if not every target has the same
+    # PkgTargetRoot so let's not worry about that here.
+    my @shlib = qx(go list -linkshared -f '{{ .Shlib }}' @targets);
+    if (@shlib) {
+        my $line = $shlib[0];
+        chomp($line);
+        return $line;
+    }
+}
+
+sub build_shlib {
+    my $this = shift;
+    my $config = $this->{shlibconfig};
+
+    my $ldflags = "-r '' -extldflags=-Wl,-soname=" . $config->{soname};
+
+    my @targets = get_targets();
+
+    $this->doit_in_builddir(
+        "go", "install", "-v", buildX(), "-ldflags", $ldflags,
+        "-buildmode=shared", "-linkshared", @targets);
+
+    my $shlib = go_shlib_path();
+    my $dsodir = dirname($shlib);
+
+    $this->doit_in_builddir("mv", "$shlib", "$dsodir/" . $config->{soname});
+    $this->doit_in_builddir("ln", "-s", $config->{soname}, "$shlib");
+
+    $this->doit_in_builddir(
+        "go", "install", "-v", buildX(), "-ldflags", "-r ''",
+        "-buildmode=exe", "-linkshared", @targets);
+}
+
 sub build {
     my $this = shift;
 
-    $ENV{GOPATH} = $this->{cwd} . '/' . $this->get_builddir();
+    $this->set_GOPATH();
     if (exists($ENV{DH_GOLANG_GO_GENERATE}) && $ENV{DH_GOLANG_GO_GENERATE} == 1) {
         $this->doit_in_builddir("go", "generate", "-v", @_, get_targets());
     }
-    $this->doit_in_builddir("go", "install", "-v", @_, get_targets());
+
+    if ($this->{shlibconfig}->{libpkg}) {
+        $this->build_shlib();
+    } elsif ($this->{shlibconfig}->{linkshared}) {
+        $this->doit_in_builddir(
+            "go", "install", buildX(), "-v", "-ldflags=-r ''", "-linkshared", @_, get_targets());
+    } else {
+        $this->doit_in_builddir("go", "install", "-v", @_, get_targets());
+    }
 }
 
 sub test {
     my $this = shift;
 
-    $ENV{GOPATH} = $this->{cwd} . '/' . $this->get_builddir();
+    $this->set_GOPATH();
+
     $this->doit_in_builddir("go", "test", "-v", @_, get_targets());
 }
 
@@ -175,16 +298,63 @@
     my $destdir = shift;
     my $builddir = $this->get_builddir();
 
+    $this->set_GOPATH();
+
     my @binaries = <$builddir/bin/*>;
     if (@binaries > 0) {
         $this->doit_in_builddir('mkdir', '-p', "$destdir/usr");
         $this->doit_in_builddir('cp', '-r', 'bin', "$destdir/usr");
     }
 
-    # Path to the src/ directory within $destdir
-    my $dest_src = "$destdir/usr/share/gocode/src/$ENV{DH_GOPKG}";
-    $this->doit_in_builddir('mkdir', '-p', $dest_src);
-    $this->doit_in_builddir('cp', '-r', '-T', "src/$ENV{DH_GOPKG}", $dest_src);
+    if ($this->{shlibconfig}->{libpkg}) {
+        my $config = $this->{shlibconfig};
+        # Here we are shuffling files about for two packages:
+        # 1) The lib package, which just contains usr/lib/$triplet/$soname
+        # 2) The dev package, which contains:
+        #    a) the source at usr/share/gocode/src/$ENV{DH_GOPKG}
+        #    b) the .a files at usr/lib/$triplet/gocode/pkg/*_dynlink/$ENV{DH_GOPKG}
+        #    c) the .so symlink at usr/lib/$triplet/gocode/pkg/*_dynlink/lib${foo}.so to the lib as
+        #       installed by 1) (${foo} is determined by the go tool and we do not make
+        #       any assumptions about it here)
+        #    d) a symlink from usr/lib/$triplet/gocode/src/$ENV{DH_GOPKG} to
+        #       usr/share/gocode/src/$ENV{DH_GOPKG}
+        my $solink = go_shlib_path();
+
+        # lib package
+        my $shlib = dirname($solink) . "/" . $config->{soname};
+        my $final_shlib_dir = "/usr/lib/" . dpkg_architecture_value("DEB_HOST_MULTIARCH");
+        my $shlibdest = tmpdir($config->{libpkg}) . $final_shlib_dir;
+        doit('mkdir', '-p', $shlibdest);
+        doit('mv', $shlib, $shlibdest);
+
+        # dev package
+        # a) source
+        my $dest_src = tmpdir($config->{devpkg}) . "/usr/share/gocode/src/$ENV{DH_GOPKG}";
+        doit('mkdir', '-p', $dest_src);
+        doit('cp', '-r', '-T', "$builddir/src/$ENV{DH_GOPKG}", $dest_src);
+
+        my $dest_lib_prefix = tmpdir($config->{devpkg}) . $final_shlib_dir . "/gocode/";
+        my $goos_goarch_dynlink = basename((<$builddir/pkg/*_dynlink>)[0]);
+
+        # b) .a files (this copies the symlink too but that will get overwritten in the next step)
+        my $dest_pkg = $dest_lib_prefix . "pkg/$goos_goarch_dynlink";
+        doit('mkdir', '-p', $dest_pkg);
+        doit('cp', '-r', '-T', "$builddir/pkg/$goos_goarch_dynlink", $dest_pkg);
+
+        # c) .so symlink
+        my $dest_solink = $dest_lib_prefix . "pkg/$goos_goarch_dynlink/" . basename($solink);
+        doit('ln', '-s', '-f', '-T', $final_shlib_dir . "/" . $config->{soname}, $dest_solink);
+
+        # d) src symlink
+        my $dest_srclink = $dest_lib_prefix . "src/$ENV{DH_GOPKG}";
+        doit('mkdir', '-p', dirname($dest_srclink));
+        doit('ln', '-s', '-T', "/usr/share/gocode/src/$ENV{DH_GOPKG}", $dest_srclink);
+    } else {
+        # Path to the src/ directory within $destdir
+        my $dest_src = "$destdir/usr/share/gocode/src/$ENV{DH_GOPKG}";
+        $this->doit_in_builddir('mkdir', '-p', $dest_src);
+        $this->doit_in_builddir('cp', '-r', '-T', "src/$ENV{DH_GOPKG}", $dest_src);
+    }
 }
 
 sub clean {
diff -Nru dh-golang-1.12/lib/Debian/Debhelper/Sequence/golang.pm dh-golang-1.12ubuntu1/lib/Debian/Debhelper/Sequence/golang.pm
--- dh-golang-1.12/lib/Debian/Debhelper/Sequence/golang.pm	2015-07-25 22:36:34.000000000 +1200
+++ dh-golang-1.12ubuntu1/lib/Debian/Debhelper/Sequence/golang.pm	2015-12-16 13:30:47.000000000 +1300
@@ -4,6 +4,8 @@
 use Debian::Debhelper::Dh_Lib;
 
 insert_before('dh_gencontrol', 'dh_golang');
+insert_before('dh_makeshlibs', 'dh_makegolangshlibs');
+remove_command('dh_makeshlibs');
 
 # XXX: -u is deprecated, but we cannot use “-- -Zxz” because additional command
 # options will be appended (“-O--buildsystem=golang”), resulting in
diff -Nru dh-golang-1.12/Makefile.PL dh-golang-1.12ubuntu1/Makefile.PL
--- dh-golang-1.12/Makefile.PL	2015-07-25 22:36:34.000000000 +1200
+++ dh-golang-1.12ubuntu1/Makefile.PL	2015-12-16 13:30:47.000000000 +1300
@@ -4,6 +4,7 @@
 version '1.0';
 
 install_script 'dh_golang';
+install_script 'dh_makegolangshlibs';
 
 #postamble <<'END_OF_MAKEFILE';
 #install:: extra_install
diff -Nru dh-golang-1.12/script/dh_makegolangshlibs dh-golang-1.12ubuntu1/script/dh_makegolangshlibs
--- dh-golang-1.12/script/dh_makegolangshlibs	1970-01-01 12:00:00.000000000 +1200
+++ dh-golang-1.12ubuntu1/script/dh_makegolangshlibs	2015-12-18 15:15:54.000000000 +1300
@@ -0,0 +1,87 @@
+#!/usr/bin/perl -w
+
+=head1 NAME
+
+dh_makegolangshlibs - Generates golang-specific shlibs files and substvars
+
+=cut
+
+use strict;
+use Debian::Debhelper::Dh_Lib;
+use File::Find;
+use MIME::Base64;
+
+=head1 SYNOPSIS
+
+B<dh_makegolangshlibs> [S<I<debhelper options>>]
+
+=head1 DESCRIPTION
+
+B<dh_makegolangshlibs> is a debhelper program which generates a
+substvar and shlibs file to enable packages depending on go shared
+libraries to conveniently depend on the ABI hash of the library rather
+than just the soversion.  It replaces dh_makeshlibs in the usual dh
+sequences.
+
+=head1 NOTES
+
+The best way to invoke B<dh_makegolangshlibs> is by using B<dh --with=golang>.
+
+=cut
+
+init();
+
+############################################################################
+# Generate ...
+############################################################################
+
+my ($libpkg, $devpkg, $libname, $sover);
+
+foreach my $pkg (@{$dh{DOPACKAGES}}) {
+    if ($pkg =~ /^lib(golang.*?)-?([0-9]+)$/) {
+        $libpkg = $pkg;
+        $libname = $1;
+        $sover = $2;
+    }
+    if ($pkg =~ /-dev$/) {
+        $devpkg = $pkg;
+    }
+}
+
+if (!defined($libpkg)) {
+    exit(0);
+} elsif (!defined($devpkg)) {
+    printf("found lib package but not dev");
+    exit(1);
+}
+
+my $sofile = sprintf(
+    "%s/usr/lib/%s/lib%s.so.%s",
+    tmpdir($libpkg), dpkg_architecture_value("DEB_HOST_MULTIARCH"),
+    $libname, $sover);
+
+my $hexhash=`/usr/lib/go/pkg/readabihash $sofile`;
+chomp($hexhash);
+
+my $libpkgdir=tmpdir($libpkg);
+if (! -d "$libpkgdir/DEBIAN") {
+    doit("install","-d","$libpkgdir/DEBIAN");
+}
+my $provides = "$libpkg-$hexhash";
+addsubstvar($libpkg, "golang:Provides", $provides);
+complex_doit("echo 'lib$libname $sover $provides' >>$libpkgdir/DEBIAN/shlibs");
+autoscript($libpkg,"postinst","postinst-makeshlibs");
+autoscript($libpkg,"postrm","postrm-makeshlibs");
+
+
+=head1 SEE ALSO
+
+dh(1)
+
+=head1 AUTHORS
+
+Michael Hudson-Doyle <michael.hudson at canonical.com>
+
+=cut
+
+# vim:ts=4:sw=4:et


More information about the pkg-golang-devel mailing list