(Spec file generators) |
Matthickford (talk | contribs) (add link to go packaging guidelines) |
||
(39 intermediate revisions by 11 users not shown) | |||
Line 1: | Line 1: | ||
{{Draft}} | {{Draft}} | ||
{{Admon/warning | This page is now obsolete | | |||
It has been superseded by official [https://docs.fedoraproject.org/en-US/packaging-guidelines/Golang/ Go packaging guidelines]. Since those guidelines rely on tooling enhancements, not available before Fedora 31, this page is kept as an unofficial guide to how things were done before. | |||
If you feel the new guidelines are not detailed enough, take a look at the packaging templates provided in the new ''go-rpm-templates'' package. | |||
}} | |||
{{Admon/note|Future plans|The [[More_Go_packaging|More Go Packaging]] other possible WIP/not yet implemented packaging guidelines proposal/extension}} | |||
= Naming = | = Naming = | ||
A SIG for people who are interested in improving the state of Golang in Fedora. | |||
= Meetings = | |||
There will be informal Go SIG meetings in the #fedora-meeting channel held irregularly. | |||
= IRC Channel = | |||
Besides the Go SIG meetings, there is also existing a freenode channel for developers and users of java in Fedora: #fedora-golang | |||
== Package Names == | == Package Names == | ||
The package name idiom for the golang is that the import paths of libraries are fully qualified domain names. This way you have clarity to the precise upstream being used. We'll acknowledge this qualified path in the Provides, but also the package name should indicate the upstream project as much as possible. Truncating domain names and using '-' instead of '/'. For example, 'github.com/gorilla/context' would be 'golang-github-gorilla-context' for the base RPM name. Similarly, the 'code.google.com/p/go.net' repository would be 'golang-googlecode-net' base RPM name. | The package name idiom for the golang is that the import paths of libraries are fully qualified domain names. This way you have a clarity to the precise upstream being used. We'll acknowledge this qualified path in the Provides, but also the package name should indicate the upstream project as much as possible. Truncating domain names and using '-' instead of '/'. For example, 'github.com/gorilla/context' would be 'golang-github-gorilla-context' for the base RPM name. Similarly, the 'code.google.com/p/go.net' repository would be 'golang-googlecode-net' base RPM name. | ||
== Import Path == | == Import Path == | ||
In the golang library paths | In the golang library, paths are referenced in full URLs. Since this URL is referenced in several places throughout the rpmspec, as a standard, set the base import path as a global define at the top of the spec file | ||
<pre> | <pre> | ||
%global | %global import_path code.google.com/p/go.net | ||
</pre> | </pre> | ||
== Versions == | == Versions == | ||
Many Go libraries do not use package versions or have regular releases | Many Go libraries do not use package versions or have regular releases and are instead maintained in public version control. In this case, follow the [https://fedoraproject.org/wiki/Packaging:NamingGuidelines#Package_Versioning standard Fedora version conventions]. This means that often Go packages will have a version number of "0" and a release number like "0.10.git27435c6". | ||
To make that version and release string easier to manage, set global defines for the project's revision (and short revision if needed). | To make that version and release string easier to manage, set global defines for the project's revision (and short revision if needed). | ||
=== Hashed revisions === | === Hashed revisions === | ||
Projects can be hosted in hashed version control systems, e.g. git, hg/mercurial. For hg/mercurial, the defines would look like: | |||
<pre> | <pre> | ||
%global rev 84a4013f96e01fdd14b65d260a78b543e3702ee1 | %global rev 84a4013f96e01fdd14b65d260a78b543e3702ee1 | ||
%global shortrev %(r=%{rev}; echo ${r:0:12}) | %global shortrev %(r=%{rev}; echo ${r:0:12}) | ||
</pre> | |||
For git, the defines would look like: | |||
<pre> | |||
%global commit 84a4013f96e01fdd14b65d260a78b543e3702ee1 | |||
%global commitdate 20150502 | |||
%global shortcommit %(c=%{commit}; echo ${c:0:7}) | |||
</pre> | </pre> | ||
Then the Release: can be set as: | Then the Release: can be set as: | ||
<pre> | <pre> | ||
Release: 0.10.hg%{shortrev}%{?dist} | Release: 0.10.%{commitdate}hg%{shortrev}%{?dist} | ||
</pre> | |||
Or as: | |||
<pre> | |||
Release: 0.10.%{commitdate}git%{shortcommit}%{?dist} | |||
</pre> | </pre> | ||
Line 54: | Line 84: | ||
If that project does also include source libraries, then a subpackage can be produced with the "golang" prefix and Provides: for the import paths that are packaged. | If that project does also include source libraries, then a subpackage can be produced with the "golang" prefix and Provides: for the import paths that are packaged. | ||
By default, the golang compiler produces static binaries (in Go sense) for all native golang source code. There is a C bridge logic CGo that allows golang source to dynamically or statically link to C compiled shared objects (e.g. libssl). | |||
All golang binary packages have an automatic exception to the standard policy. | All golang binary packages have an automatic exception to the standard policy. | ||
The GCC-Go compiler by default produces dynamically-linked binaries and is capable of statically linking as well. | The GCC-Go compiler by default produces dynamically-linked binaries and is capable of statically linking as well. | ||
At this stage, the reference compiler is the golang compiler, though gccgo is ready for use, and has demonstrated performance benefits for isolated use-cases. | At this stage, the reference compiler is the golang compiler("GC"), though gccgo is ready for use, and has demonstrated performance benefits for isolated use-cases. | ||
== Build ID == | == Build ID == | ||
The golang compiler (`gc`) does provide by default the ".note.gnu.build-id" section that GCC does. Though, if the binary being built supports being compiled with `gccgo`, the gccgo compiler does support and include the .note.gnu.build-id. | The golang compiler (`gc`) does '''not''' provide by default the ".note.gnu.build-id" section that GCC does. Though, if the binary being built supports being compiled with `gccgo`, the gccgo compiler does support and include the .note.gnu.build-id. | ||
== Debuginfo == | == Debuginfo == | ||
Line 79: | Line 109: | ||
</pre> | </pre> | ||
There is | On Fedora, buildroots installing golang also installs go-compilers-golang-compiler rpm, which provides %gobuild macro. | ||
It automatically sets the build ID. | |||
If the ldflags needs to be extended further, you can set LDFLAGS environment variable. | |||
<pre> | |||
export LDFLAGS="-X %{import_path}/version.GitSHA=%{shortcommit}" | |||
%gobuild -o bin/BINARY %{import_path}/cmd/CMD | |||
</pre> | |||
There is a historical bug for the debug-info [https://bugzilla.redhat.com/show_bug.cgi?id=1184221 Bug 1184221] that is fixed now. | |||
If you hit a new bug, please fill a new ticket. | |||
== Dependencies == | == Dependencies == | ||
Most of the golang-* packages are source code only | Most of the golang-* packages are source code only. The *-devel sub-package that includes the source code should explicitly have provides for the golang imports that it includes ''(without single or double quotes)''. | ||
Binary builds that include these imports will use BuildRequires: | Binary builds that include these imports will use BuildRequires: | ||
<pre> | <pre> | ||
BuildRequires: golang(github.com/gorilla/context) >= 0-0.13 | BuildRequires: golang(github.com/gorilla/context) >= 0-0.13 | ||
</pre> | </pre> | ||
== Go Language Architectures == | == Go Language Architectures == | ||
The golang compiler currently | To compile on various architectures, golang and gcc-go compilers are available. The golang compiler currently supports x86, x86_64, ppc64le, ppc64(partially, [https://github.com/golang/go/issues/13192 see upstream issue#13192]), s390x, armv7hl and aarch64. Binaries should set <code>ExclusiveArch</code> so that we only attempt to build packages on those arches. The <code>go-srpm-macros</code> package provides the <code>%{go_arches}</code> macro for this: | ||
<pre> | <pre> | ||
ExclusiveArch: %{go_arches} | ExclusiveArch: %{go_arches} | ||
</pre> | </pre> | ||
{{Admon/note|ppc64 Big-endian only|Please note that since Fedora 27, ppc64 is dropped from the macros, effectively disabling build on ppc64 for all packages adhering to this guidelines. This has been done due to moving of GC to support only Power8 and up and general feature miss-parity of GC port. Switch to gcc-go hasn't been done as it potentially requires non-trivial amount of packaging work from packages. Both golang and gcc-go are still available for those architectures, although with the mentioned limitation on golang("GC") side.}} | |||
To make choose of given compiler independent of an architecture, go-compilers package is introduced. It provides compiler(go-compiler) virtual provide that can be used: | |||
<pre> | |||
BuildRequires: compiler(go-compiler) | |||
</pre> | |||
It installs the correct compiler (golang or gcc-go). If the package is to be compiled only by golang or gcc-go, compiler(golang) and compiler(gcc-go) are available as well. This way there is no need to set a minimal version for each compiler (gcc-go is provided by gcc >= 5.0.0) as it is already enforced in go-compiler package itself. go-compilers package also defines %gobuild (with generating Build ID when debug is enabled) and %gotest macros that can be used to build and test golang project: | |||
<pre> | |||
%gobuild -o bin/NAME %{import_path} | |||
</pre> | |||
<pre> | |||
%gotest %{import_path}/package | |||
</pre> | |||
%gobuild macro can be used with -o option. It is not recommended to use any other options as they can be compiler specific. For compiler specific options use corresponding virtual provide and 'go build', resp. 'go build -compiler gccgo' build command. The same reasoning for testing options holds here. In most cases, it should be sufficient. | |||
Example of spec file with support for available architectures: | |||
<pre> | |||
# [...] | |||
Name: golang-%{provider}-%{project}-%{repo} | |||
Version: 1 | |||
Release: 13%{?dist} | |||
Summary: Process markdown into manpages | |||
License: MIT | |||
URL: https://%{import_path} | |||
Source0: https://%{import_path}/archive/%{commit}/%{repo}-%{shortcommit}.tar.gz | |||
# e.g. el6 has ppc64 arch without gcc-go, so EA tag is required | |||
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 %{arm}} | |||
# If go_compiler is not set to 1, there is no virtual provide. Use golang instead. | |||
BuildRequires: %{?go_compiler:compiler(go-compiler)}%{!?go_compiler:golang} | |||
# [...] | |||
%prep | |||
%setup -q -n %{repo}-%{commit} | |||
%build | |||
mkdir -p src/github.com/cpuguy83 | |||
ln -s ../../../ src/github.com/cpuguy83/go-md2man | |||
%if ! 0%{?with_bundled} | |||
export GOPATH=$(pwd):%{gopath} | |||
%else | |||
echo "Unable to build from bundled deps. No Godeps nor vendor directory" | |||
exit 1 | |||
%endif | |||
%gobuild -o bin/go-md2man %{import_path} | |||
%install | |||
# install go-md2man binary | |||
install -d %{buildroot}%{_bindir} | |||
install -p -m 755 bin/%{repo} %{buildroot}%{_bindir} | |||
# [...] | |||
%endif | |||
# [...] | |||
%check | |||
%if 0%{?with_check} && 0%{?with_unit_test} && 0%{?with_devel} | |||
export GOPATH=%{buildroot}/%{gopath}:%{gopath} | |||
%gotest %{import_path}/generator | |||
%gotest %{import_path}/parser | |||
%endif | |||
# [...] | |||
</pre> | |||
== Bundled or de-bundled == | |||
At the moment golang projects packaged in Fedora (resp. epel6) branches are de-bundled by default. | |||
It means projects are built from dependencies packaged in Fedora (resp. epel6). | |||
For other branches (and projects) it can be reasonable to build from bundled dependencies. | |||
For epel7, there is a chance a package will get into RHEL7. | |||
Thus, causing the removal of the package from epel7 repository. | |||
Be aware, this is not a general rule. Every bundling needs a proper justification!!! | |||
See https://fedorahosted.org/fesco/ticket/1483#comment:17 and https://fedoraproject.org/wiki/EPEL/GuidelinesAndPolicies#Policy for more information. | |||
= Packaging Libraries = | = Packaging Libraries = | ||
Line 101: | Line 228: | ||
At this time, Go libraries packaged in Fedora are primarily for the purpose of being BuildRequires for building Fedora binary RPMs, and not meant to be developed against otherwise -- for that, we encourage the upstream "go get" idiom and a per-user $GOPATH. | At this time, Go libraries packaged in Fedora are primarily for the purpose of being BuildRequires for building Fedora binary RPMs, and not meant to be developed against otherwise -- for that, we encourage the upstream "go get" idiom and a per-user $GOPATH. | ||
As mentioned we do not provide or recommend a system-wide GOPATH that users should inherit and there is no notion of a "site" or "vendor" path for system libraries. Although you can set GOPATH in a way that will include the system path in per-user GOPATH (e.g. export GOPATH=$HOME/go:/usr/share/gocode). This way a call to `go get ...` would land new source in the $HOME/go directory. But be aware the system libraries may change significantly during live of the release, as mentioned. | |||
GOROOT is reserved for golang standard library only. | GOROOT is reserved for golang standard library only. | ||
By default, the standard golang compiler produces static libraries. There is little value in shipping these prebuilt, especially since these libraries are very specifically tied to the exact minor release of the golang compiler. Instead, each library package should consist of a -devel subpackage which installs .go source code to /usr/share/gocode/src, under the appropriate import path. | |||
Binary packages which build against this source will set $GOPATH to '%{_datadir}/gocode' ( or '%{gopath}' in golang > 1.2.1-1) | Binary packages which build against this source will set $GOPATH to '%{_datadir}/gocode' ( or '%{gopath}' in golang > 1.2.1-1) | ||
Line 111: | Line 238: | ||
== Shared-object libraries == | == Shared-object libraries == | ||
Presently the shared object libraries produced by GCC-Go are not usable [https://gcc.gnu.org/ml/gcc-help/2011-06/msg00239.html]. | |||
It is not a blocker for supported architectures using cgo to have dynamic links to a C/C++ compiled shared-object library [http://golang.org/cmd/cgo/]. | |||
== Dependencies == | == Dependencies == | ||
Line 173: | Line 299: | ||
== Branching macros == | == Branching macros == | ||
For some packaged binaries it is impossible to provide debugging information, some binaries | For some packaged binaries it is impossible to provide debugging information, some binaries cannot be built from de-bundled dependencies, provided tests need an internet connection in order to work properly. For these use cases, it is convenient to add with_debug, with_bundled, and with_check macros, wrap parts of spec file and set the macros accordingly. Other macros as with_devel can be used to wrap devel subpackage parts and install commands. E.g. | ||
<pre> | <pre> | ||
%if 0%{?fedora} | # If any of the following macros should be set otherwise, | ||
# you can wrap any of them with the following conditions: | |||
# - %%if 0%%{centos} == 7 | |||
# - %%if 0%%{?rhel} == 7 | |||
# - %%if 0%%{?fedora} == 23 | |||
# Or just test for particular distribution: | |||
# - %%if 0%%{centos} | |||
# - %%if 0%%{?rhel} | |||
# - %%if 0%%{?fedora} | |||
# | |||
# Be aware, on centos, both %%rhel and %%centos are set. If you want to test | |||
# rhel specific macros, you can use %%if 0%%{?rhel} && 0%%{?centos} == 0 condition. | |||
# (Don't forget to replace double percentage symbol with single one in order to apply a condition) | |||
# Generate devel rpm | |||
%global with_devel 1 | %global with_devel 1 | ||
# Build project from bundled dependencies | |||
%global with_bundled 0 | %global with_bundled 0 | ||
%global with_debug | # Build with debug info rpm | ||
%global with_debug 0 | |||
# Run tests in check section | |||
%global with_check 1 | %global with_check 1 | ||
# Generate unit-test rpm | |||
%global with_unit_test 1 | |||
%global | |||
# [...] | # [...] | ||
Line 200: | Line 340: | ||
%if 0%{?with_devel} | %if 0%{?with_devel} | ||
%package devel | %package devel | ||
BuildArch: noarch | |||
# [...] | # [...] | ||
Line 215: | Line 355: | ||
ln -s ../../../ src/github.com/coreos/etcd | ln -s ../../../ src/github.com/coreos/etcd | ||
# [...] | # [...] | ||
% | %gobuild -o bin/etcd %{import_path} | ||
%gobuild -o bin/etcdctl %{import_path}/etcdctl | |||
%gobuild -o bin/etcd-migrate %{import_path}/tools/%{name}-migrate | |||
gobuild -o bin/etcd %{import_path} | |||
gobuild -o bin/etcdctl %{import_path}/etcdctl | |||
gobuild -o bin/etcd-migrate %{import_path}/tools/%{name}-migrate | |||
%else | %else | ||
./build | ./build | ||
Line 258: | Line 393: | ||
== Check of dependencies == | == Check of dependencies == | ||
After an update of a package a list of provided and imported packages can change. In order to get a list of missing or superfluous provided and imported packages, one can use [https://github.com/ingvagabund/gofed gofed tool] by | After an update of a package, a list of provided and imported packages can change. In order to get a list of missing or superfluous provided and imported packages, one can use [https://github.com/ingvagabund/gofed gofed tool] by running 'gofed lint' in a repository directory: | ||
<pre> | <pre> | ||
Line 284: | Line 419: | ||
The command inspects project's tarball, sources file and compares a list of provided/imported packages in spec file with those in tarball. | The command inspects project's tarball, sources file and compares a list of provided/imported packages in spec file with those in tarball. | ||
As some packages have different name for a devel subpackage (e.g. golang-googlecode-net package has golang-golangorg-net-devel devel subpackage), which subpackage is the devel subpackage has to be specified by setting devel_main macro. At the same time if a devel subpackage has different import path than the one specified in %{import_path} macro, devel_prefix macro has to be set in order for 'gofed lint' to check the correct subpackage. | As some packages have a different name for a devel subpackage (e.g. golang-googlecode-net package has golang-golangorg-net-devel devel subpackage), which subpackage is the devel subpackage has to be specified by setting devel_main macro. At the same time if a devel subpackage has different import path than the one specified in %{import_path} macro, devel_prefix macro has to be set in order for 'gofed lint' to check the correct subpackage. | ||
<pre> | <pre> | ||
Line 306: | Line 441: | ||
%global devel_main golang-golangorg-net-devel | %global devel_main golang-golangorg-net-devel | ||
# all macros belonging to golang-golangorg-net-devel subpackage | # all macros belonging to golang-golangorg-net-devel subpackage | ||
# are defined by the same macros names as for main package | # are defined by the same macros names as for the main package | ||
# but prefixed with x_, i.e. x_provider, x_import_path, ... | # but prefixed with x_, i.e. x_provider, x_import_path, ... | ||
%global devel_prefix x | %global devel_prefix x | ||
Line 320: | Line 455: | ||
</pre> | </pre> | ||
If your package has different devel subpackage or | If your package has different devel subpackage or uses different %{import_path} macro, please specify devel_main and devel_prefix macros. | ||
= Spec file generators = | = Spec file generators = | ||
Spec files for 'packaging a library' as described above can be generated via [https://github.com/ingvagabund/gofed gofed tool]. | Spec files for 'packaging a library' as described above can be generated via [https://github.com/ingvagabund/gofed gofed tool]. | ||
At the moment it supports generators for github.com, code.google.com and bitbucket.org. Generated spec files conform to the current golang packaging guidelines and are ready to use. | At the moment it supports generators for github.com, code.google.com, and bitbucket.org. Generated spec files conform to the current golang packaging guidelines and are ready to use. | ||
Summary and License has to be modified manually. Generated spec file can be further extended based on a specific projects (some directories have to be removed, | |||
description or summary extended, %doc extended for other important documents, etc.). Some projects provide main packages which can be built. | description or summary extended, %doc extended for other important documents, etc.). Some projects provide main packages which can be built. | ||
As a building process for each project is specific (via go build, make, hack/make.sh etc.) the generator keeps %build section empty. Neither debuginfo nor with_* macros are generated. | As a building process for each project is specific (via go build, make, hack/make.sh etc.) the generator keeps %build section empty. Neither debuginfo nor with_* macros are generated. | ||
Line 332: | Line 467: | ||
= Sample RPM Spec= | = Sample RPM Spec= | ||
Following a couple of | Following a couple of examples RPM spec files to give a sample layout for future packagers of libraries or applications written in golang. | ||
== Packaging a library == | == Packaging a library == | ||
<pre> | <pre> | ||
%global | %global import_path code.google.com/p/go.net | ||
%global rev 84a4013f96e01fdd14b65d260a78b543e3702ee1 | %global rev 84a4013f96e01fdd14b65d260a78b543e3702ee1 | ||
%global shortrev %(r=%{rev}; echo ${r:0:12}) | %global shortrev %(r=%{rev}; echo ${r:0:12}) | ||
Line 345: | Line 480: | ||
Summary: Supplementary Go networking libraries | Summary: Supplementary Go networking libraries | ||
License: BSD | License: BSD | ||
URL: http://%{ | URL: http://%{import_path} | ||
Source0: https://net.go.googlecode.com/archive/%{rev}.zip | Source0: https://net.go.googlecode.com/archive/%{rev}.zip | ||
% | |||
# e.g. el6 has ppc64 arch without gcc-go, so EA tag is required | |||
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 ppc64le s390x | |||
# If go_compiler is not set to 1, there is no virtual provide. Use golang instead. | |||
% | BuildRequires: %{?go_compiler:compiler(go-compiler)}%{!?go_compiler:golang} | ||
%description | %description | ||
Line 358: | Line 492: | ||
%package devel | %package devel | ||
Summary: Supplementary Go networking libraries | Summary: Supplementary Go networking libraries | ||
Provides: golang(%{ | |||
Provides: golang(%{ | Provides: golang(%{import_path}) = %{version}-%{release} | ||
Provides: golang(%{import_path}/dict) = %{version}-%{release} | |||
# [...] | # [...] | ||
Line 379: | Line 513: | ||
%install | %install | ||
install -d %{buildroot}/%{gopath}/src/%{ | install -d %{buildroot}/%{gopath}/src/%{import_path} | ||
for d in dict html idna ipv4 ipv6 proxy publicsuffix spdy websocket; do | for d in dict html idna ipv4 ipv6 proxy publicsuffix spdy websocket; do | ||
cp -avp $d %{buildroot}/%{gopath}/src/%{ | cp -avp $d %{buildroot}/%{gopath}/src/%{import_path}/ | ||
done | done | ||
%check | %check | ||
GOPATH=%{buildroot}/%{gopath} go test %{ | GOPATH=%{buildroot}/%{gopath} go test %{import_path}/html | ||
# [...] | # [...] | ||
%files devel | %files devel | ||
%doc AUTHORS CONTRIBUTORS LICENSE PATENTS README | %doc AUTHORS CONTRIBUTORS LICENSE PATENTS README | ||
%doc README-webkit | %doc README-webkit | ||
%dir %attr(755,root,root) %{gopath}/src/%{ | %dir %attr(755,root,root) %{gopath}/src/%{import_path} | ||
%dir %attr(755,root,root) %{gopath}/src/%{ | %dir %attr(755,root,root) %{gopath}/src/%{import_path}/dict | ||
%dir %attr(755,root,root) %{gopath}/src/%{ | %dir %attr(755,root,root) %{gopath}/src/%{import_path}/html | ||
# [...] | # [...] | ||
%{gopath}/src/%{ | %{gopath}/src/%{import_path}/dict/*.go | ||
%{gopath}/src/%{ | %{gopath}/src/%{import_path}/html/*.go | ||
# [...] | # [...] | ||
%changelog | %changelog | ||
* Fri Jul 11 2014 | * Fri Jul 11 2014 Jill User <jill.user@fedoraproject.org> - 0-0.15.hg84a4013f96e0 | ||
- don't fail on ipv6 test bz1056185 | - don't fail on ipv6 test bz1056185 | ||
# [...] | # [...] | ||
</pre> | </pre> | ||
== Packaging a binary == | == Packaging a binary == | ||
Line 414: | Line 546: | ||
Name: example-app | Name: example-app | ||
Version: 1.0.0 | Version: 1.0.0 | ||
Release: | Release: 1%{?dist} | ||
Summary: This application is an example for the golang binary RPM spec | Summary: This application is an example for the golang binary RPM spec | ||
License: ASL 2.0 | License: ASL 2.0 | ||
URL: http://www.example-app.io | URL: http://www.example-app.io | ||
Source0: https://github.com/example/app/archive/v%{version}.tar.gz | Source0: https://github.com/example/app/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz | ||
Source1: example-app.service | Source1: example-app.service | ||
Source2: example-app.sysconfig | Source2: example-app.sysconfig | ||
Line 434: | Line 566: | ||
%prep | %prep | ||
% | %autosetup -n %{name}-%{version} | ||
# many golang binaries are "vendoring" (bundling) sources, so remove them. Those dependencies need to be packaged independently. | # many golang binaries are "vendoring" (bundling) sources, so remove them. Those dependencies need to be packaged independently. | ||
Line 452: | Line 584: | ||
%files | %files | ||
%doc AUTHORS CHANGELOG.md CONTRIBUTING.md FIXME LICENSE MAINTAINERS NOTICE README.md | %doc AUTHORS CHANGELOG.md CONTRIBUTING.md FIXME LICENSE MAINTAINERS NOTICE README.md | ||
%{_bindir}/example-app | %{_bindir}/example-app | ||
%changelog | %changelog | ||
* Tue Jul 01 2014 Jill User <jill.user@fedoraproject.org> - 1.0.0- | * Tue Jul 01 2014 Jill User <jill.user@fedoraproject.org> - 1.0.0-1 | ||
- package the example-app | - package the example-app | ||
</pre> | |||
= Thanks = | = Thanks = | ||
Line 467: | Line 598: | ||
= Discussion = | = Discussion = | ||
See [[Talk:PackagingDrafts/Go]] for discussion. | See [[Talk:PackagingDrafts/Go]] and https://fedorahosted.org/fpc/ticket/382 for discussion. | ||
[[Category:Packaging guidelines drafts]] | [[Category:Packaging guidelines drafts]] |
Latest revision as of 15:53, 15 January 2023
Naming
A SIG for people who are interested in improving the state of Golang in Fedora.
Meetings
There will be informal Go SIG meetings in the #fedora-meeting channel held irregularly.
IRC Channel
Besides the Go SIG meetings, there is also existing a freenode channel for developers and users of java in Fedora: #fedora-golang
Package Names
The package name idiom for the golang is that the import paths of libraries are fully qualified domain names. This way you have a clarity to the precise upstream being used. We'll acknowledge this qualified path in the Provides, but also the package name should indicate the upstream project as much as possible. Truncating domain names and using '-' instead of '/'. For example, 'github.com/gorilla/context' would be 'golang-github-gorilla-context' for the base RPM name. Similarly, the 'code.google.com/p/go.net' repository would be 'golang-googlecode-net' base RPM name.
Import Path
In the golang library, paths are referenced in full URLs. Since this URL is referenced in several places throughout the rpmspec, as a standard, set the base import path as a global define at the top of the spec file
%global import_path code.google.com/p/go.net
Versions
Many Go libraries do not use package versions or have regular releases and are instead maintained in public version control. In this case, follow the standard Fedora version conventions. This means that often Go packages will have a version number of "0" and a release number like "0.10.git27435c6".
To make that version and release string easier to manage, set global defines for the project's revision (and short revision if needed).
Hashed revisions
Projects can be hosted in hashed version control systems, e.g. git, hg/mercurial. For hg/mercurial, the defines would look like:
%global rev 84a4013f96e01fdd14b65d260a78b543e3702ee1 %global shortrev %(r=%{rev}; echo ${r:0:12})
For git, the defines would look like:
%global commit 84a4013f96e01fdd14b65d260a78b543e3702ee1 %global commitdate 20150502 %global shortcommit %(c=%{commit}; echo ${c:0:7})
Then the Release: can be set as:
Release: 0.10.%{commitdate}hg%{shortrev}%{?dist}
Or as:
Release: 0.10.%{commitdate}git%{shortcommit}%{?dist}
Numerical revisions
For projects that use a numerical version control (bzr), then the defines would look like:
%global rev 53
Then the Release: can be set as:
Release: 0.10.bzr%{rev}%{?dist}
Packaging Binaries
Applications that have a 'main' package name, are compiled to a binary. These should be named after the upstream project, and do not need a "golang" prefix.
If that project does also include source libraries, then a subpackage can be produced with the "golang" prefix and Provides: for the import paths that are packaged.
By default, the golang compiler produces static binaries (in Go sense) for all native golang source code. There is a C bridge logic CGo that allows golang source to dynamically or statically link to C compiled shared objects (e.g. libssl). All golang binary packages have an automatic exception to the standard policy.
The GCC-Go compiler by default produces dynamically-linked binaries and is capable of statically linking as well.
At this stage, the reference compiler is the golang compiler("GC"), though gccgo is ready for use, and has demonstrated performance benefits for isolated use-cases.
Build ID
The golang compiler (gc
) does not provide by default the ".note.gnu.build-id" section that GCC does. Though, if the binary being built supports being compiled with gccgo
, the gccgo compiler does support and include the .note.gnu.build-id.
Debuginfo
If you are using golang, DWZ is currently incompatible with binaries produced by it (Bug 995136). To get at least partial DWZ optimization use:
# https://bugzilla.redhat.com/show_bug.cgi?id=995136#c12 %global _dwz_low_mem_die_limit 0
If you are using golang, it does not produce build ID by default. Use this compilation command otherwise build ID packaging check would stop the package build:
# *** ERROR: No build ID note found in /.../BUILDROOT/etcd-2.0.0-1.rc1.fc22.x86_64/usr/bin/etcd function gobuild { go build -a -ldflags "-B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \n')" -v -x "$@"; }
On Fedora, buildroots installing golang also installs go-compilers-golang-compiler rpm, which provides %gobuild macro. It automatically sets the build ID. If the ldflags needs to be extended further, you can set LDFLAGS environment variable.
export LDFLAGS="-X %{import_path}/version.GitSHA=%{shortcommit}" %gobuild -o bin/BINARY %{import_path}/cmd/CMD
There is a historical bug for the debug-info Bug 1184221 that is fixed now. If you hit a new bug, please fill a new ticket.
Dependencies
Most of the golang-* packages are source code only. The *-devel sub-package that includes the source code should explicitly have provides for the golang imports that it includes (without single or double quotes). Binary builds that include these imports will use BuildRequires:
BuildRequires: golang(github.com/gorilla/context) >= 0-0.13
Go Language Architectures
To compile on various architectures, golang and gcc-go compilers are available. The golang compiler currently supports x86, x86_64, ppc64le, ppc64(partially, see upstream issue#13192), s390x, armv7hl and aarch64. Binaries should set ExclusiveArch
so that we only attempt to build packages on those arches. The go-srpm-macros
package provides the %{go_arches}
macro for this:
ExclusiveArch: %{go_arches}
To make choose of given compiler independent of an architecture, go-compilers package is introduced. It provides compiler(go-compiler) virtual provide that can be used:
BuildRequires: compiler(go-compiler)
It installs the correct compiler (golang or gcc-go). If the package is to be compiled only by golang or gcc-go, compiler(golang) and compiler(gcc-go) are available as well. This way there is no need to set a minimal version for each compiler (gcc-go is provided by gcc >= 5.0.0) as it is already enforced in go-compiler package itself. go-compilers package also defines %gobuild (with generating Build ID when debug is enabled) and %gotest macros that can be used to build and test golang project:
%gobuild -o bin/NAME %{import_path}
%gotest %{import_path}/package
%gobuild macro can be used with -o option. It is not recommended to use any other options as they can be compiler specific. For compiler specific options use corresponding virtual provide and 'go build', resp. 'go build -compiler gccgo' build command. The same reasoning for testing options holds here. In most cases, it should be sufficient.
Example of spec file with support for available architectures:
# [...] Name: golang-%{provider}-%{project}-%{repo} Version: 1 Release: 13%{?dist} Summary: Process markdown into manpages License: MIT URL: https://%{import_path} Source0: https://%{import_path}/archive/%{commit}/%{repo}-%{shortcommit}.tar.gz # e.g. el6 has ppc64 arch without gcc-go, so EA tag is required ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 %{arm}} # If go_compiler is not set to 1, there is no virtual provide. Use golang instead. BuildRequires: %{?go_compiler:compiler(go-compiler)}%{!?go_compiler:golang} # [...] %prep %setup -q -n %{repo}-%{commit} %build mkdir -p src/github.com/cpuguy83 ln -s ../../../ src/github.com/cpuguy83/go-md2man %if ! 0%{?with_bundled} export GOPATH=$(pwd):%{gopath} %else echo "Unable to build from bundled deps. No Godeps nor vendor directory" exit 1 %endif %gobuild -o bin/go-md2man %{import_path} %install # install go-md2man binary install -d %{buildroot}%{_bindir} install -p -m 755 bin/%{repo} %{buildroot}%{_bindir} # [...] %endif # [...] %check %if 0%{?with_check} && 0%{?with_unit_test} && 0%{?with_devel} export GOPATH=%{buildroot}/%{gopath}:%{gopath} %gotest %{import_path}/generator %gotest %{import_path}/parser %endif # [...]
Bundled or de-bundled
At the moment golang projects packaged in Fedora (resp. epel6) branches are de-bundled by default. It means projects are built from dependencies packaged in Fedora (resp. epel6). For other branches (and projects) it can be reasonable to build from bundled dependencies. For epel7, there is a chance a package will get into RHEL7. Thus, causing the removal of the package from epel7 repository. Be aware, this is not a general rule. Every bundling needs a proper justification!!! See https://fedorahosted.org/fesco/ticket/1483#comment:17 and https://fedoraproject.org/wiki/EPEL/GuidelinesAndPolicies#Policy for more information.
Packaging Libraries
At this time, Go libraries packaged in Fedora are primarily for the purpose of being BuildRequires for building Fedora binary RPMs, and not meant to be developed against otherwise -- for that, we encourage the upstream "go get" idiom and a per-user $GOPATH.
As mentioned we do not provide or recommend a system-wide GOPATH that users should inherit and there is no notion of a "site" or "vendor" path for system libraries. Although you can set GOPATH in a way that will include the system path in per-user GOPATH (e.g. export GOPATH=$HOME/go:/usr/share/gocode). This way a call to go get ...
would land new source in the $HOME/go directory. But be aware the system libraries may change significantly during live of the release, as mentioned.
GOROOT is reserved for golang standard library only.
By default, the standard golang compiler produces static libraries. There is little value in shipping these prebuilt, especially since these libraries are very specifically tied to the exact minor release of the golang compiler. Instead, each library package should consist of a -devel subpackage which installs .go source code to /usr/share/gocode/src, under the appropriate import path.
Binary packages which build against this source will set $GOPATH to '%{_datadir}/gocode' ( or '%{gopath}' in golang > 1.2.1-1)
Presently the shared object libraries produced by GCC-Go are not usable [1].
It is not a blocker for supported architectures using cgo to have dynamic links to a C/C++ compiled shared-object library [2].
Dependencies
To match the fully qualified import paths of the projects and source, utilize the meta wrapper / virtual provides in the golang namespace to provide the import paths being packaged.
Most of the golang-* packages are source code only, the *-devel sub-package that includes the source code, should explicitly have provides for the golang imports that it includes. (without single or double quotes)
Provides: golang(%{go_import_path}) = %{version}-%{release}
Then other source packages that reference these imports can have Requires: matching that:
Requires: golang(github.com/gorilla/context)
Libraries and Arch
Because these packages contain no compiled code, they should be made noarch. However, since they require golang, they need to only be built on the architectures supported by the language. For that reason, follow the standard guidelines for noarch packages with unported dependencies:
BuildArch: noarch ExclusiveArch: %{go_arches} noarch
Security in Go Language Packages
If there is a security issue in the standard Go library or in a library built into binary Go programs, all affected RPMs will need to be rebuilt.
In the event that a security issue is found in a library, all packages which have that library as a BuildRequires must be identified and rebuilt with the version and release of the fixed library added to the BuildRequires.
repoquery -q --disablerepo='*' --enablerepo=fedora-source --enablerepo=updates-source --enablerepo=updates-testing-source --archlist=src --whatrequires 'golang($SOME_IMPORT_PATH)'
Additionally, other golang-*-devel packages may directly require their own dependencies; check for such packages with
repoquery -q --disablerepo='*' --enablerepo=fedora --enablerepo=updates --enablerepo=updates-testing --whatrequires 'golang($SOME_IMPORT_PATH)'
and, if any of the results are golang-*-devel RPMs, repeat the previous step to find packages which may have that as a BuildRequires.
Optional
List of dependencies
Some projects like kubernetes, cadvisor or etcd ship a list of dependencies they require for building. The list is located under Godeps directory in Godeps.json file. It maps each imported path to its corresponding commit. The list can be used by scripts to automatically check if all imported paths are packaged and up-to-date in Fedora.
Other projects like docker use vendor directory to store a list of dependencies instead of Godeps.
If the list of dependencies is provided it is good to include it in %doc in %files section of the spec file.
Branching macros
For some packaged binaries it is impossible to provide debugging information, some binaries cannot be built from de-bundled dependencies, provided tests need an internet connection in order to work properly. For these use cases, it is convenient to add with_debug, with_bundled, and with_check macros, wrap parts of spec file and set the macros accordingly. Other macros as with_devel can be used to wrap devel subpackage parts and install commands. E.g.
# If any of the following macros should be set otherwise, # you can wrap any of them with the following conditions: # - %%if 0%%{centos} == 7 # - %%if 0%%{?rhel} == 7 # - %%if 0%%{?fedora} == 23 # Or just test for particular distribution: # - %%if 0%%{centos} # - %%if 0%%{?rhel} # - %%if 0%%{?fedora} # # Be aware, on centos, both %%rhel and %%centos are set. If you want to test # rhel specific macros, you can use %%if 0%%{?rhel} && 0%%{?centos} == 0 condition. # (Don't forget to replace double percentage symbol with single one in order to apply a condition) # Generate devel rpm %global with_devel 1 # Build project from bundled dependencies %global with_bundled 0 # Build with debug info rpm %global with_debug 0 # Run tests in check section %global with_check 1 # Generate unit-test rpm %global with_unit_test 1 # [...] %if 0%{?with_debug} %global _dwz_low_mem_die_limit 0 %else %global debug_package %{nil} %endif # [...] %if 0%{?with_devel} %package devel BuildArch: noarch # [...] %description devel # [...] %endif # [...] %build %if ! 0%{?with_bundled} # Make link for etcd itself mkdir -p src/github.com/coreos ln -s ../../../ src/github.com/coreos/etcd # [...] %gobuild -o bin/etcd %{import_path} %gobuild -o bin/etcdctl %{import_path}/etcdctl %gobuild -o bin/etcd-migrate %{import_path}/tools/%{name}-migrate %else ./build %endif # [...] %install # [...] %if 0%{?with_devel} # Install files for devel sub-package install -d %{buildroot}/%{gopath}/src/%{import_path} cp -pav main.go %{buildroot}/%{gopath}/src/%{import_path}/ for dir in client discovery error; do cp -rpav ${dir} %{buildroot}/%{gopath}/src/%{import_path}/ done %endif # [...] %check %if 0%{?with_check} %if 0%{?with_bundled} export GOPATH=$(pwd)/Godeps/_workspace:%{gopath} %else export GOPATH=%{buildroot}%{gopath}:%{gopath} %endif go test %{import_path}/client go test %{import_path}/discovery %endif # [...]
Check of dependencies
After an update of a package, a list of provided and imported packages can change. In order to get a list of missing or superfluous provided and imported packages, one can use gofed tool by running 'gofed lint' in a repository directory:
$ basename $(pwd) golang-googlecode-net $ ls golang-googlecode-net.spec net-7dbad50.tar.gz sources $ gofed lint 1 golang specfile checked; 0 errors, 0 warnings.
If some 'Provides' or 'BuildRequires' are missing:
$ gofed lint W: Missing BuildRequires: golang(golang.org/x/text/encoding/korean) W: Missing BuildRequires: golang(golang.org/x/text/encoding/simplifiedchinese) W: Missing BuildRequires: golang(golang.org/x/text/encoding/traditionalchinese) W: Missing Provides: golang(golang.org/x/net/internal/iana) W: Missing Provides: golang(golang.org/x/net/internal/nettest) W: Missing Provides: golang(golang.org/x/net/ipv4) W: Missing Provides: golang(golang.org/x/net/ipv6) 1 golang specfile checked; 0 errors, 7 warnings.
The command inspects project's tarball, sources file and compares a list of provided/imported packages in spec file with those in tarball. As some packages have a different name for a devel subpackage (e.g. golang-googlecode-net package has golang-golangorg-net-devel devel subpackage), which subpackage is the devel subpackage has to be specified by setting devel_main macro. At the same time if a devel subpackage has different import path than the one specified in %{import_path} macro, devel_prefix macro has to be set in order for 'gofed lint' to check the correct subpackage.
%global provider_tld com %global provider github %global project golang %global repo net %global import_path code.google.com/p/go.net %global commit 7dbad50ab5b31073856416cdcfeb2796d682f844 %global shortcommit %(c=%{commit}; echo ${c:0:7}) # primary devel subpackage %global x_provider golang %global x_provider_tld org %global x_repo net %global x_import_path %{x_provider}.%{x_provider_tld}/x/%{x_repo} %global x_name golang-%{x_provider}%{x_provider_tld}-%{repo} # here the package name is golang-googlecode-net # but the devel subpackage is golang-golangorg-net-devel %global devel_main golang-golangorg-net-devel # all macros belonging to golang-golangorg-net-devel subpackage # are defined by the same macros names as for the main package # but prefixed with x_, i.e. x_provider, x_import_path, ... %global devel_prefix x # [...] Name: golang-googlecode-net Version: 0 Release: 0.21.git%{shortcommit}%{?dist} Summary: Supplementary Go networking libraries # [...]
If your package has different devel subpackage or uses different %{import_path} macro, please specify devel_main and devel_prefix macros.
Spec file generators
Spec files for 'packaging a library' as described above can be generated via gofed tool. At the moment it supports generators for github.com, code.google.com, and bitbucket.org. Generated spec files conform to the current golang packaging guidelines and are ready to use. Summary and License has to be modified manually. Generated spec file can be further extended based on a specific projects (some directories have to be removed, description or summary extended, %doc extended for other important documents, etc.). Some projects provide main packages which can be built. As a building process for each project is specific (via go build, make, hack/make.sh etc.) the generator keeps %build section empty. Neither debuginfo nor with_* macros are generated.
Sample RPM Spec
Following a couple of examples RPM spec files to give a sample layout for future packagers of libraries or applications written in golang.
Packaging a library
%global import_path code.google.com/p/go.net %global rev 84a4013f96e01fdd14b65d260a78b543e3702ee1 %global shortrev %(r=%{rev}; echo ${r:0:12}) Name: golang-googlecode-net Version: 0 Release: 0.15.hg%{shortrev}%{?dist} Summary: Supplementary Go networking libraries License: BSD URL: http://%{import_path} Source0: https://net.go.googlecode.com/archive/%{rev}.zip # e.g. el6 has ppc64 arch without gcc-go, so EA tag is required ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 ppc64le s390x # If go_compiler is not set to 1, there is no virtual provide. Use golang instead. BuildRequires: %{?go_compiler:compiler(go-compiler)}%{!?go_compiler:golang} %description %{summary} %package devel Summary: Supplementary Go networking libraries Provides: golang(%{import_path}) = %{version}-%{release} Provides: golang(%{import_path}/dict) = %{version}-%{release} # [...] %description devel %{summary} This package contains library source intended for building other packages which use the supplementary Go networking libraries. %prep %setup -n net.go-%{shortrev} cp html/testdata/webkit/README README-webkit %build %install install -d %{buildroot}/%{gopath}/src/%{import_path} for d in dict html idna ipv4 ipv6 proxy publicsuffix spdy websocket; do cp -avp $d %{buildroot}/%{gopath}/src/%{import_path}/ done %check GOPATH=%{buildroot}/%{gopath} go test %{import_path}/html # [...] %files devel %doc AUTHORS CONTRIBUTORS LICENSE PATENTS README %doc README-webkit %dir %attr(755,root,root) %{gopath}/src/%{import_path} %dir %attr(755,root,root) %{gopath}/src/%{import_path}/dict %dir %attr(755,root,root) %{gopath}/src/%{import_path}/html # [...] %{gopath}/src/%{import_path}/dict/*.go %{gopath}/src/%{import_path}/html/*.go # [...] %changelog * Fri Jul 11 2014 Jill User <jill.user@fedoraproject.org> - 0-0.15.hg84a4013f96e0 - don't fail on ipv6 test bz1056185 # [...]
Packaging a binary
%global commit 63fe64c471e7d76be96a625350468dfc65c06c31 %global shortcommit %(c=%{commit}; echo ${c:0:7}) Name: example-app Version: 1.0.0 Release: 1%{?dist} Summary: This application is an example for the golang binary RPM spec License: ASL 2.0 URL: http://www.example-app.io Source0: https://github.com/example/app/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz Source1: example-app.service Source2: example-app.sysconfig BuildRequires: gcc BuildRequires: golang >= 1.2-7 # pull in golang libraries by explicit import path, inside the meta golang() BuildRequires: golang(github.com/gorilla/mux) >= 0-0.13 [...] %description # include your full description of the application here. %prep %autosetup -n %{name}-%{version} # many golang binaries are "vendoring" (bundling) sources, so remove them. Those dependencies need to be packaged independently. rm -rf vendor %build # set up temporary build gopath, and put our directory there mkdir -p ./_build/src/github.com/example ln -s $(pwd) ./_build/src/github.com/example/app export GOPATH=$(pwd)/_build:%{gopath} go build -o example-app . %install install -d %{buildroot}%{_bindir} install -p -m 0755 ./example-app %{buildroot}%{_bindir}/example-app %files %doc AUTHORS CHANGELOG.md CONTRIBUTING.md FIXME LICENSE MAINTAINERS NOTICE README.md %{_bindir}/example-app %changelog * Tue Jul 01 2014 Jill User <jill.user@fedoraproject.org> - 1.0.0-1 - package the example-app
Thanks
These guidelines are Fedora-specific but are intended to match Debian practice where that is reasonable.
Discussion
See Talk:PackagingDrafts/Go and https://fedorahosted.org/fpc/ticket/382 for discussion.