https://en.opensuse.org/api.php?action=feedcontributions&user=MargueriteSu&feedformat=atomopenSUSE Wiki - User contributions [en]2024-03-29T10:29:09ZUser contributionsMediaWiki 1.37.6https://en.opensuse.org/index.php?title=Portal:Cinnamon/Team&diff=118351Portal:Cinnamon/Team2016-12-17T04:27:30Z<p>MargueriteSu: </p>
<hr />
<div>* {{User|cyberorg}} – Initial packages.<br />
* {{User|ketheriel}} – Cinnamon 1.2 packages.<br />
* {{User|MargueriteSu}} – Cinnamon 2.0 - 2.6 packages.<br />
* [https://build.opensuse.org/user/show/XRevan86 XRevan86] – Cinnamon 2.8 packages and bringing back to life.<font color=red>alive</font><br />
* [https://build.opensuse.org/user/show/linuxrecon linuxrecon] – Co-maintainer.<br />
* [https://build.opensuse.org/user/show/jluce2 jluce2] – Co-maintainer.<br />
<br />
Welcome to join! Just read the `help us out` section in the left.</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=71681openSUSE:Packaging Go2015-07-26T04:35:45Z<p>MargueriteSu: /* Macros */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About golang =<br />
<br />
Go (or golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming scheme =<br />
<br />
Please note that golang packages follow a strict naming convention, with exceptions for convenience.<br />
<br />
Golang packages' names begin with a prefix "golang-", follow a string modified from $IMPORTPATH, which is the "url" (actually it's a path) when you `go get`. Technically $IMPORTPATH looks like the "include <xxx.h>" in C, "require 'xx'" in Ruby or "from package import function" in Python, but in a format "import golang.org/google/api". In this case "golang.org/google/api" is the $IMPORTPATH.<br />
<br />
It can be taken as three parts: vendor => golang.org, author => google, pkg => api. Here's how we modify it to the following string in golang packages' names:<br />
<br />
vender: usually we use the common known name of the vendor, eg. "github.com" will be "github" and "code.google.com/p/" will be "googlecode". When there's no common known name for a vendor, eg. "gopkg.in", we just skip the "dot" in the vendor url, that is "gopkgin".<br />
<br />
author: usually this part is unique enough, most of them are people names, so we just keep it as it is. And it can also be skipped in some cases. eg: "code.google.com/p/xxx", there's no author in the importpath at all (not the "p"). But in other cases it must be explicitly kept, eg "golang.org/x/net", the "x" here means that it's some kind of "standard libraries", so it must be kept. And the "nsf" in "github.com/nsf/gocode" can't be skipped at all.<br />
<br />
pkg: usually we just keep it as it is. But when there's a string "go" somewhere in the upstream package name:<br />
* go-XX: skip the "go", we don't want to see package name like "golang-github-xxx-go-xxx", the "golang-" prefix indentifies it already<br />
* XX.go: this is old history back to Go1 era. just skip the "go"<br />
* goXX: keep the "go" because it is "in" the package name, not prefix or suffix.<br />
<br />
= Versioning scheme =<br />
<br />
Most golang packages did not follow a strict version scheme yet. You should use the date when you retrieved the upstream (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+gitYYYYMMDD, eg 0.0.0+git20150726, or you can let our Build Service do it for you via a _service file. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
= Development repository &amp; process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository in the openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in <tt>/tmp</tt>, and install the compiled codes in <tt>~/go/pkg/linux_${go_arch}/</tt>. (a combination of download, `<tt>go build</tt>` and `<tt>go install</tt>`.)<br />
<br />
So just like other new scripting languages, e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find it has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from <tt>$GOROOT</tt> (where go itself installs) and <tt>$GOPATH</tt> (where go packages installs). You can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, inside the build infrastructure, it will be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
Within plain environments, it would be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in the build log, <!-- shown as error, --> it will be different because the compilers of go (such things like 6g 6l...) will:<br />
<br />
'''1st''': try to find the compiled dependencies in the above path<br />
<br />
'''2nd''': try to find source code of the dependencies in the paths mentioned below, compile them, install them to the <tt>$GOPATH</tt> of the user operating go, then use them as dependencies.<br />
<br />
Within the build infrastructure:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
Within plain environments:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
'''3rd (only able in `go get` mode)''': download source code to the <tt>$GOPATH</tt> of the user operating go and repeat the 2nd step.<br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step because you carelessly used the `<tt>go get</tt>` method to replace the default <tt>%gobuild</tt> macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
The standard directory layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
The '''contrib''' directory is used for 3rd-party implementations (usually our packages). But in <tt>~/go</tt>, Go will place compiled codes in <tt>pkg</tt> and source code into <tt>src</tt> directly (no <tt>contrib</tt> directory at all).<br />
<br />
= The easy and the stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2015, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$STRING<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source: $EXACT_UPSTREAM_NAME-%{version}.tar.xz<br />
BuildRequires: golang-packaging<br />
BuildRequires: xxx-devel<br />
BuildRequires: xz<br />
Requires: xxx-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_provides}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%gosrc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME-%{version}<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%goinstall<br />
%gosrc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files source<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros, because some macros like <tt>%go_exclusivearch</tt> are for internal use and have already been included in other macros).<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually, you already have had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in golang packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, <tt>%goprep</tt>, <tt>%gofix</tt>, <tt>%gobuild</tt>, <tt>%goinstall</tt>, <tt>%gosrc</tt>, <tt>%gotest</tt> are macros that can not be quoted because they allow arguments. So please double-check after you run "spec-cleaner -i xxx.spec", which will quote such macros.<br />
<br />
=== %go_ver ===<br />
<br />
It will return golang's version like '''1.4.2'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
'''Deprecated''', should not be used in newer packages<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the common shared library detection mechanism (/sbin/ldconfig) will not find dependencies for it. That is, <tt>%go_requires</tt> itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will add '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages do not have header files. They are statically built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
'''Deprecated''', should not be used on newer packages<br />
<br />
It will add '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
'''Deprecated''', use %gosrc_package instead.<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the homepage for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
'''Deprecated''', use %gosrc instead.<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against newer golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ===<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
== Packaging tricks for Go ==<br />
<br />
=== "tags" in go get ===<br />
<br />
Sometimes upstream e.g. gozmq told you to "go get -tags xxx $IMPORTPATH" to get a specific version , and they put files for all tags together in one repository. What's worse, newer tags like "zmq_4_x" needs files from older tags like "zmq_3_x" and "zmq_2_2" to build (Maybe that's why upstream didn't split files into different git branches). Plus the "*_test.go" files, they totally get us confused about which file can be deleted for the build of a specific version.<br />
<br />
So we can't simply deleted "zmq_3_x" files for "zmq_4_x" builds, and considering the "*_test.go" files, it'll be a total mess for us to use "%{?suse_version}" to delete files (illogic, changeable all the time). All in all, "go get -tags" is the perfect, most simple, and (maybe) only possible way.<br />
<br />
In this case, we need to manually "construct" a "go get" to replace %gobuild. As [[#Where will Golang find dependencies?]] shows, "go get" will try to find sources in $GOPATH before actually downloading online (the later will certainly break because OBS build VM doesn't have any network), it indicates that if we put sources at the right place (%goprep) and export the correct envrionment variables, "go get" is '''usuable''' on OBS. So we can change commands in specfiles like this:<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
%gobuild<br />
<br />
%install<br />
%goinstall<br />
<br />
to<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
# manual build<br />
export IMPORTPATH="github.com/alecthomas/gozmq"<br />
export BUILDFLAGS="-s -v -p 4 -x"<br />
export GOPATH=%{_builddir}/go:%{_libdir}/go/contrib<br />
%if 0%{?suse_version} >= 1230<br />
%if 0%{?suse_version} > 1315<br />
go get --tags zmq_4_x $BUILDFLAGS $IMPORTPATH<br />
%else<br />
go get --tags zmq_3_x $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
%else<br />
go get --tags zmq_2_1 $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
<br />
%install<br />
%goinstall<br />
<br />
=== $GOTOOLDIR is not rewritable ===<br />
<br />
Sometimes when building Go official packages e.g. go.tools, some binraries like "godoc" will force to install themselves into %{_libdir}/go/pkg/tool/linux_%{go_arch}, even if you have recontructed the %gobuild macro and exported GOTOOLDIR to %{_builddir}/go/pkg/tool/linux_%{go_arch}.<br />
<br />
This is intentional because Go upstream doesn't want official tools like godoc to be separately updated without the rest of go tools. But as go.tools is separately built from go main package, such decision will trigger "open /usr/lib64/go/pkg/tool/linux_amd64: Permission Denied" error on OBS.<br />
<br />
We patched go main package and provided a macro called "GOROOT_TARGET". If you:<br />
<br />
export GOROOT_TARGET="%{buildroot}%{_libdir}/go"<br />
<br />
before %gobuild, you can get this workaround.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=71680openSUSE:Packaging Go2015-07-26T04:25:40Z<p>MargueriteSu: /* The easy and the stupid way */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About golang =<br />
<br />
Go (or golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming scheme =<br />
<br />
Please note that golang packages follow a strict naming convention, with exceptions for convenience.<br />
<br />
Golang packages' names begin with a prefix "golang-", follow a string modified from $IMPORTPATH, which is the "url" (actually it's a path) when you `go get`. Technically $IMPORTPATH looks like the "include <xxx.h>" in C, "require 'xx'" in Ruby or "from package import function" in Python, but in a format "import golang.org/google/api". In this case "golang.org/google/api" is the $IMPORTPATH.<br />
<br />
It can be taken as three parts: vendor => golang.org, author => google, pkg => api. Here's how we modify it to the following string in golang packages' names:<br />
<br />
vender: usually we use the common known name of the vendor, eg. "github.com" will be "github" and "code.google.com/p/" will be "googlecode". When there's no common known name for a vendor, eg. "gopkg.in", we just skip the "dot" in the vendor url, that is "gopkgin".<br />
<br />
author: usually this part is unique enough, most of them are people names, so we just keep it as it is. And it can also be skipped in some cases. eg: "code.google.com/p/xxx", there's no author in the importpath at all (not the "p"). But in other cases it must be explicitly kept, eg "golang.org/x/net", the "x" here means that it's some kind of "standard libraries", so it must be kept. And the "nsf" in "github.com/nsf/gocode" can't be skipped at all.<br />
<br />
pkg: usually we just keep it as it is. But when there's a string "go" somewhere in the upstream package name:<br />
* go-XX: skip the "go", we don't want to see package name like "golang-github-xxx-go-xxx", the "golang-" prefix indentifies it already<br />
* XX.go: this is old history back to Go1 era. just skip the "go"<br />
* goXX: keep the "go" because it is "in" the package name, not prefix or suffix.<br />
<br />
= Versioning scheme =<br />
<br />
Most golang packages did not follow a strict version scheme yet. You should use the date when you retrieved the upstream (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+gitYYYYMMDD, eg 0.0.0+git20150726, or you can let our Build Service do it for you via a _service file. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
= Development repository &amp; process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository in the openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in <tt>/tmp</tt>, and install the compiled codes in <tt>~/go/pkg/linux_${go_arch}/</tt>. (a combination of download, `<tt>go build</tt>` and `<tt>go install</tt>`.)<br />
<br />
So just like other new scripting languages, e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find it has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from <tt>$GOROOT</tt> (where go itself installs) and <tt>$GOPATH</tt> (where go packages installs). You can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, inside the build infrastructure, it will be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
Within plain environments, it would be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in the build log, <!-- shown as error, --> it will be different because the compilers of go (such things like 6g 6l...) will:<br />
<br />
'''1st''': try to find the compiled dependencies in the above path<br />
<br />
'''2nd''': try to find source code of the dependencies in the paths mentioned below, compile them, install them to the <tt>$GOPATH</tt> of the user operating go, then use them as dependencies.<br />
<br />
Within the build infrastructure:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
Within plain environments:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
'''3rd (only able in `go get` mode)''': download source code to the <tt>$GOPATH</tt> of the user operating go and repeat the 2nd step.<br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step because you carelessly used the `<tt>go get</tt>` method to replace the default <tt>%gobuild</tt> macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
The standard directory layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
The '''contrib''' directory is used for 3rd-party implementations (usually our packages). But in <tt>~/go</tt>, Go will place compiled codes in <tt>pkg</tt> and source code into <tt>src</tt> directly (no <tt>contrib</tt> directory at all).<br />
<br />
= The easy and the stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2015, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$STRING<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source: $EXACT_UPSTREAM_NAME-%{version}.tar.xz<br />
BuildRequires: golang-packaging<br />
BuildRequires: xxx-devel<br />
BuildRequires: xz<br />
Requires: xxx-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_provides}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%gosrc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME-%{version}<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%goinstall<br />
%gosrc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files source<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros, because some macros like <tt>%go_disable_brp_strip_static_archive</tt> and <tt>%go_exclusivearch</tt> are for internal use and have already be included in other macros).<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually, you already have had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, <tt>%goprep</tt>, <tt>%gofix</tt>, <tt>%gobuild</tt>, <tt>%goinstall</tt>, <tt>%godoc</tt>, <tt>%gotest</tt> are macros that can not be quoted.<br />
Because they allow arguments. So please double-check after you run "spec-cleaner -i xxx.spec", which will quote such macros.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the common shared library detection mechanism (/sbin/ldconfig) will not find dependencies for it. That is, <tt>%go_requires</tt> itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will add '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages do not have header files. They are statically built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will add '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ===<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
== Packaging tricks for Go ==<br />
<br />
=== "tags" in go get ===<br />
<br />
Sometimes upstream e.g. gozmq told you to "go get -tags xxx $IMPORTPATH" to get a specific version , and they put files for all tags together in one repository. What's worse, newer tags like "zmq_4_x" needs files from older tags like "zmq_3_x" and "zmq_2_2" to build (Maybe that's why upstream didn't split files into different git branches). Plus the "*_test.go" files, they totally get us confused about which file can be deleted for the build of a specific version.<br />
<br />
So we can't simply deleted "zmq_3_x" files for "zmq_4_x" builds, and considering the "*_test.go" files, it'll be a total mess for us to use "%{?suse_version}" to delete files (illogic, changeable all the time). All in all, "go get -tags" is the perfect, most simple, and (maybe) only possible way.<br />
<br />
In this case, we need to manually "construct" a "go get" to replace %gobuild. As [[#Where will Golang find dependencies?]] shows, "go get" will try to find sources in $GOPATH before actually downloading online (the later will certainly break because OBS build VM doesn't have any network), it indicates that if we put sources at the right place (%goprep) and export the correct envrionment variables, "go get" is '''usuable''' on OBS. So we can change commands in specfiles like this:<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
%gobuild<br />
<br />
%install<br />
%goinstall<br />
<br />
to<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
# manual build<br />
export IMPORTPATH="github.com/alecthomas/gozmq"<br />
export BUILDFLAGS="-s -v -p 4 -x"<br />
export GOPATH=%{_builddir}/go:%{_libdir}/go/contrib<br />
%if 0%{?suse_version} >= 1230<br />
%if 0%{?suse_version} > 1315<br />
go get --tags zmq_4_x $BUILDFLAGS $IMPORTPATH<br />
%else<br />
go get --tags zmq_3_x $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
%else<br />
go get --tags zmq_2_1 $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
<br />
%install<br />
%goinstall<br />
<br />
=== $GOTOOLDIR is not rewritable ===<br />
<br />
Sometimes when building Go official packages e.g. go.tools, some binraries like "godoc" will force to install themselves into %{_libdir}/go/pkg/tool/linux_%{go_arch}, even if you have recontructed the %gobuild macro and exported GOTOOLDIR to %{_builddir}/go/pkg/tool/linux_%{go_arch}.<br />
<br />
This is intentional because Go upstream doesn't want official tools like godoc to be separately updated without the rest of go tools. But as go.tools is separately built from go main package, such decision will trigger "open /usr/lib64/go/pkg/tool/linux_amd64: Permission Denied" error on OBS.<br />
<br />
We patched go main package and provided a macro called "GOROOT_TARGET". If you:<br />
<br />
export GOROOT_TARGET="%{buildroot}%{_libdir}/go"<br />
<br />
before %gobuild, you can get this workaround.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=71679openSUSE:Packaging Go2015-07-26T04:23:13Z<p>MargueriteSu: /* Where will Golang find dependencies? */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About golang =<br />
<br />
Go (or golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming scheme =<br />
<br />
Please note that golang packages follow a strict naming convention, with exceptions for convenience.<br />
<br />
Golang packages' names begin with a prefix "golang-", follow a string modified from $IMPORTPATH, which is the "url" (actually it's a path) when you `go get`. Technically $IMPORTPATH looks like the "include <xxx.h>" in C, "require 'xx'" in Ruby or "from package import function" in Python, but in a format "import golang.org/google/api". In this case "golang.org/google/api" is the $IMPORTPATH.<br />
<br />
It can be taken as three parts: vendor => golang.org, author => google, pkg => api. Here's how we modify it to the following string in golang packages' names:<br />
<br />
vender: usually we use the common known name of the vendor, eg. "github.com" will be "github" and "code.google.com/p/" will be "googlecode". When there's no common known name for a vendor, eg. "gopkg.in", we just skip the "dot" in the vendor url, that is "gopkgin".<br />
<br />
author: usually this part is unique enough, most of them are people names, so we just keep it as it is. And it can also be skipped in some cases. eg: "code.google.com/p/xxx", there's no author in the importpath at all (not the "p"). But in other cases it must be explicitly kept, eg "golang.org/x/net", the "x" here means that it's some kind of "standard libraries", so it must be kept. And the "nsf" in "github.com/nsf/gocode" can't be skipped at all.<br />
<br />
pkg: usually we just keep it as it is. But when there's a string "go" somewhere in the upstream package name:<br />
* go-XX: skip the "go", we don't want to see package name like "golang-github-xxx-go-xxx", the "golang-" prefix indentifies it already<br />
* XX.go: this is old history back to Go1 era. just skip the "go"<br />
* goXX: keep the "go" because it is "in" the package name, not prefix or suffix.<br />
<br />
= Versioning scheme =<br />
<br />
Most golang packages did not follow a strict version scheme yet. You should use the date when you retrieved the upstream (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+gitYYYYMMDD, eg 0.0.0+git20150726, or you can let our Build Service do it for you via a _service file. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
= Development repository &amp; process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository in the openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in <tt>/tmp</tt>, and install the compiled codes in <tt>~/go/pkg/linux_${go_arch}/</tt>. (a combination of download, `<tt>go build</tt>` and `<tt>go install</tt>`.)<br />
<br />
So just like other new scripting languages, e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find it has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from <tt>$GOROOT</tt> (where go itself installs) and <tt>$GOPATH</tt> (where go packages installs). You can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, inside the build infrastructure, it will be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
Within plain environments, it would be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in the build log, <!-- shown as error, --> it will be different because the compilers of go (such things like 6g 6l...) will:<br />
<br />
'''1st''': try to find the compiled dependencies in the above path<br />
<br />
'''2nd''': try to find source code of the dependencies in the paths mentioned below, compile them, install them to the <tt>$GOPATH</tt> of the user operating go, then use them as dependencies.<br />
<br />
Within the build infrastructure:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
Within plain environments:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
'''3rd (only able in `go get` mode)''': download source code to the <tt>$GOPATH</tt> of the user operating go and repeat the 2nd step.<br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step because you carelessly used the `<tt>go get</tt>` method to replace the default <tt>%gobuild</tt> macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
The standard directory layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
The '''contrib''' directory is used for 3rd-party implementations (usually our packages). But in <tt>~/go</tt>, Go will place compiled codes in <tt>pkg</tt> and source code into <tt>src</tt> directly (no <tt>contrib</tt> directory at all).<br />
<br />
= The easy and the stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRequires: xxx-devel<br />
Requires: xxx-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros, because some macros like <tt>%go_disable_brp_strip_static_archive</tt> and <tt>%go_exclusivearch</tt> are for internal use and have already be included in other macros).<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually, you already have had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, <tt>%goprep</tt>, <tt>%gofix</tt>, <tt>%gobuild</tt>, <tt>%goinstall</tt>, <tt>%godoc</tt>, <tt>%gotest</tt> are macros that can not be quoted.<br />
Because they allow arguments. So please double-check after you run "spec-cleaner -i xxx.spec", which will quote such macros.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the common shared library detection mechanism (/sbin/ldconfig) will not find dependencies for it. That is, <tt>%go_requires</tt> itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will add '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages do not have header files. They are statically built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will add '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ===<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
== Packaging tricks for Go ==<br />
<br />
=== "tags" in go get ===<br />
<br />
Sometimes upstream e.g. gozmq told you to "go get -tags xxx $IMPORTPATH" to get a specific version , and they put files for all tags together in one repository. What's worse, newer tags like "zmq_4_x" needs files from older tags like "zmq_3_x" and "zmq_2_2" to build (Maybe that's why upstream didn't split files into different git branches). Plus the "*_test.go" files, they totally get us confused about which file can be deleted for the build of a specific version.<br />
<br />
So we can't simply deleted "zmq_3_x" files for "zmq_4_x" builds, and considering the "*_test.go" files, it'll be a total mess for us to use "%{?suse_version}" to delete files (illogic, changeable all the time). All in all, "go get -tags" is the perfect, most simple, and (maybe) only possible way.<br />
<br />
In this case, we need to manually "construct" a "go get" to replace %gobuild. As [[#Where will Golang find dependencies?]] shows, "go get" will try to find sources in $GOPATH before actually downloading online (the later will certainly break because OBS build VM doesn't have any network), it indicates that if we put sources at the right place (%goprep) and export the correct envrionment variables, "go get" is '''usuable''' on OBS. So we can change commands in specfiles like this:<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
%gobuild<br />
<br />
%install<br />
%goinstall<br />
<br />
to<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
# manual build<br />
export IMPORTPATH="github.com/alecthomas/gozmq"<br />
export BUILDFLAGS="-s -v -p 4 -x"<br />
export GOPATH=%{_builddir}/go:%{_libdir}/go/contrib<br />
%if 0%{?suse_version} >= 1230<br />
%if 0%{?suse_version} > 1315<br />
go get --tags zmq_4_x $BUILDFLAGS $IMPORTPATH<br />
%else<br />
go get --tags zmq_3_x $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
%else<br />
go get --tags zmq_2_1 $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
<br />
%install<br />
%goinstall<br />
<br />
=== $GOTOOLDIR is not rewritable ===<br />
<br />
Sometimes when building Go official packages e.g. go.tools, some binraries like "godoc" will force to install themselves into %{_libdir}/go/pkg/tool/linux_%{go_arch}, even if you have recontructed the %gobuild macro and exported GOTOOLDIR to %{_builddir}/go/pkg/tool/linux_%{go_arch}.<br />
<br />
This is intentional because Go upstream doesn't want official tools like godoc to be separately updated without the rest of go tools. But as go.tools is separately built from go main package, such decision will trigger "open /usr/lib64/go/pkg/tool/linux_amd64: Permission Denied" error on OBS.<br />
<br />
We patched go main package and provided a macro called "GOROOT_TARGET". If you:<br />
<br />
export GOROOT_TARGET="%{buildroot}%{_libdir}/go"<br />
<br />
before %gobuild, you can get this workaround.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=71678openSUSE:Packaging Go2015-07-26T04:09:01Z<p>MargueriteSu: /* Versioning scheme */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About golang =<br />
<br />
Go (or golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming scheme =<br />
<br />
Please note that golang packages follow a strict naming convention, with exceptions for convenience.<br />
<br />
Golang packages' names begin with a prefix "golang-", follow a string modified from $IMPORTPATH, which is the "url" (actually it's a path) when you `go get`. Technically $IMPORTPATH looks like the "include <xxx.h>" in C, "require 'xx'" in Ruby or "from package import function" in Python, but in a format "import golang.org/google/api". In this case "golang.org/google/api" is the $IMPORTPATH.<br />
<br />
It can be taken as three parts: vendor => golang.org, author => google, pkg => api. Here's how we modify it to the following string in golang packages' names:<br />
<br />
vender: usually we use the common known name of the vendor, eg. "github.com" will be "github" and "code.google.com/p/" will be "googlecode". When there's no common known name for a vendor, eg. "gopkg.in", we just skip the "dot" in the vendor url, that is "gopkgin".<br />
<br />
author: usually this part is unique enough, most of them are people names, so we just keep it as it is. And it can also be skipped in some cases. eg: "code.google.com/p/xxx", there's no author in the importpath at all (not the "p"). But in other cases it must be explicitly kept, eg "golang.org/x/net", the "x" here means that it's some kind of "standard libraries", so it must be kept. And the "nsf" in "github.com/nsf/gocode" can't be skipped at all.<br />
<br />
pkg: usually we just keep it as it is. But when there's a string "go" somewhere in the upstream package name:<br />
* go-XX: skip the "go", we don't want to see package name like "golang-github-xxx-go-xxx", the "golang-" prefix indentifies it already<br />
* XX.go: this is old history back to Go1 era. just skip the "go"<br />
* goXX: keep the "go" because it is "in" the package name, not prefix or suffix.<br />
<br />
= Versioning scheme =<br />
<br />
Most golang packages did not follow a strict version scheme yet. You should use the date when you retrieved the upstream (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+gitYYYYMMDD, eg 0.0.0+git20150726, or you can let our Build Service do it for you via a _service file. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
= Development repository &amp; process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository in the openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in <tt>/tmp</tt>, and install the compiled codes in <tt>~/go/pkg/linux_${go_arch}/</tt>. (a combination of download, `<tt>go build</tt>` and `<tt>go install</tt>`.)<br />
<br />
So just like other new scripting languages, e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find it has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from <tt>$GOROOT</tt> (where go itself installs) and <tt>$GOPATH</tt> (where go packages installs). You can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, inside the build infrastructure, it will be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
Within plain environments, it would be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in the build log, <!-- shown as error, --> it will be different because the compilers of go (such things like 6g 6l...) will:<br />
<br />
'''1st''': try to find the compiled dependencies in the about path<br />
<br />
'''2nd''': try to find source code of the dependencies in the paths mentioned below, compile them, install them to the <tt>$GOPATH</tt> of the user operating go, then use them as dependencies.<br />
<br />
Within the build infrastructure:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
Within plain environments:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
'''3rd (only able in `go get` mode)''': download source code to the <tt>$GOPATH</tt> of the user operating go and repeat the 2nd step.<br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step unless you carelessly used the `<tt>go get</tt>` method to replace the default <tt>%gobuild</tt> macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
The standard directory layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
The '''contrib''' directory is used for 3rd-party implementations (usually our packages). But in <tt>~/go</tt>, Go will place compiled codes in <tt>pkg</tt> and source code into <tt>src</tt> directly (no <tt>contrib</tt> directory at all).<br />
<br />
= The easy and the stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRequires: xxx-devel<br />
Requires: xxx-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros, because some macros like <tt>%go_disable_brp_strip_static_archive</tt> and <tt>%go_exclusivearch</tt> are for internal use and have already be included in other macros).<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually, you already have had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, <tt>%goprep</tt>, <tt>%gofix</tt>, <tt>%gobuild</tt>, <tt>%goinstall</tt>, <tt>%godoc</tt>, <tt>%gotest</tt> are macros that can not be quoted.<br />
Because they allow arguments. So please double-check after you run "spec-cleaner -i xxx.spec", which will quote such macros.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the common shared library detection mechanism (/sbin/ldconfig) will not find dependencies for it. That is, <tt>%go_requires</tt> itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will add '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages do not have header files. They are statically built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will add '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ===<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
== Packaging tricks for Go ==<br />
<br />
=== "tags" in go get ===<br />
<br />
Sometimes upstream e.g. gozmq told you to "go get -tags xxx $IMPORTPATH" to get a specific version , and they put files for all tags together in one repository. What's worse, newer tags like "zmq_4_x" needs files from older tags like "zmq_3_x" and "zmq_2_2" to build (Maybe that's why upstream didn't split files into different git branches). Plus the "*_test.go" files, they totally get us confused about which file can be deleted for the build of a specific version.<br />
<br />
So we can't simply deleted "zmq_3_x" files for "zmq_4_x" builds, and considering the "*_test.go" files, it'll be a total mess for us to use "%{?suse_version}" to delete files (illogic, changeable all the time). All in all, "go get -tags" is the perfect, most simple, and (maybe) only possible way.<br />
<br />
In this case, we need to manually "construct" a "go get" to replace %gobuild. As [[#Where will Golang find dependencies?]] shows, "go get" will try to find sources in $GOPATH before actually downloading online (the later will certainly break because OBS build VM doesn't have any network), it indicates that if we put sources at the right place (%goprep) and export the correct envrionment variables, "go get" is '''usuable''' on OBS. So we can change commands in specfiles like this:<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
%gobuild<br />
<br />
%install<br />
%goinstall<br />
<br />
to<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
# manual build<br />
export IMPORTPATH="github.com/alecthomas/gozmq"<br />
export BUILDFLAGS="-s -v -p 4 -x"<br />
export GOPATH=%{_builddir}/go:%{_libdir}/go/contrib<br />
%if 0%{?suse_version} >= 1230<br />
%if 0%{?suse_version} > 1315<br />
go get --tags zmq_4_x $BUILDFLAGS $IMPORTPATH<br />
%else<br />
go get --tags zmq_3_x $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
%else<br />
go get --tags zmq_2_1 $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
<br />
%install<br />
%goinstall<br />
<br />
=== $GOTOOLDIR is not rewritable ===<br />
<br />
Sometimes when building Go official packages e.g. go.tools, some binraries like "godoc" will force to install themselves into %{_libdir}/go/pkg/tool/linux_%{go_arch}, even if you have recontructed the %gobuild macro and exported GOTOOLDIR to %{_builddir}/go/pkg/tool/linux_%{go_arch}.<br />
<br />
This is intentional because Go upstream doesn't want official tools like godoc to be separately updated without the rest of go tools. But as go.tools is separately built from go main package, such decision will trigger "open /usr/lib64/go/pkg/tool/linux_amd64: Permission Denied" error on OBS.<br />
<br />
We patched go main package and provided a macro called "GOROOT_TARGET". If you:<br />
<br />
export GOROOT_TARGET="%{buildroot}%{_libdir}/go"<br />
<br />
before %gobuild, you can get this workaround.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=71677openSUSE:Packaging Go2015-07-26T04:07:17Z<p>MargueriteSu: </p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About golang =<br />
<br />
Go (or golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming scheme =<br />
<br />
Please note that golang packages follow a strict naming convention, with exceptions for convenience.<br />
<br />
Golang packages' names begin with a prefix "golang-", follow a string modified from $IMPORTPATH, which is the "url" (actually it's a path) when you `go get`. Technically $IMPORTPATH looks like the "include <xxx.h>" in C, "require 'xx'" in Ruby or "from package import function" in Python, but in a format "import golang.org/google/api". In this case "golang.org/google/api" is the $IMPORTPATH.<br />
<br />
It can be taken as three parts: vendor => golang.org, author => google, pkg => api. Here's how we modify it to the following string in golang packages' names:<br />
<br />
vender: usually we use the common known name of the vendor, eg. "github.com" will be "github" and "code.google.com/p/" will be "googlecode". When there's no common known name for a vendor, eg. "gopkg.in", we just skip the "dot" in the vendor url, that is "gopkgin".<br />
<br />
author: usually this part is unique enough, most of them are people names, so we just keep it as it is. And it can also be skipped in some cases. eg: "code.google.com/p/xxx", there's no author in the importpath at all (not the "p"). But in other cases it must be explicitly kept, eg "golang.org/x/net", the "x" here means that it's some kind of "standard libraries", so it must be kept. And the "nsf" in "github.com/nsf/gocode" can't be skipped at all.<br />
<br />
pkg: usually we just keep it as it is. But when there's a string "go" somewhere in the upstream package name:<br />
* go-XX: skip the "go", we don't want to see package name like "golang-github-xxx-go-xxx", the "golang-" prefix indentifies it already<br />
* XX.go: this is old history back to Go1 era. just skip the "go"<br />
* goXX: keep the "go" because it is "in" the package name, not prefix or suffix.<br />
<br />
== Versioning scheme ==<br />
<br />
Most golang packages did not follow a strict version scheme yet. You should use the date when you retrieved the upstream (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+gitYYYYMMDD, eg 0.0.0+git20150726, or you can let our Build Service do it for you via a _service file. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
= Development repository &amp; process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository in the openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in <tt>/tmp</tt>, and install the compiled codes in <tt>~/go/pkg/linux_${go_arch}/</tt>. (a combination of download, `<tt>go build</tt>` and `<tt>go install</tt>`.)<br />
<br />
So just like other new scripting languages, e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find it has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from <tt>$GOROOT</tt> (where go itself installs) and <tt>$GOPATH</tt> (where go packages installs). You can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, inside the build infrastructure, it will be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
Within plain environments, it would be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in the build log, <!-- shown as error, --> it will be different because the compilers of go (such things like 6g 6l...) will:<br />
<br />
'''1st''': try to find the compiled dependencies in the about path<br />
<br />
'''2nd''': try to find source code of the dependencies in the paths mentioned below, compile them, install them to the <tt>$GOPATH</tt> of the user operating go, then use them as dependencies.<br />
<br />
Within the build infrastructure:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
Within plain environments:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
'''3rd (only able in `go get` mode)''': download source code to the <tt>$GOPATH</tt> of the user operating go and repeat the 2nd step.<br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step unless you carelessly used the `<tt>go get</tt>` method to replace the default <tt>%gobuild</tt> macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
The standard directory layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
The '''contrib''' directory is used for 3rd-party implementations (usually our packages). But in <tt>~/go</tt>, Go will place compiled codes in <tt>pkg</tt> and source code into <tt>src</tt> directly (no <tt>contrib</tt> directory at all).<br />
<br />
= The easy and the stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRequires: xxx-devel<br />
Requires: xxx-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros, because some macros like <tt>%go_disable_brp_strip_static_archive</tt> and <tt>%go_exclusivearch</tt> are for internal use and have already be included in other macros).<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually, you already have had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, <tt>%goprep</tt>, <tt>%gofix</tt>, <tt>%gobuild</tt>, <tt>%goinstall</tt>, <tt>%godoc</tt>, <tt>%gotest</tt> are macros that can not be quoted.<br />
Because they allow arguments. So please double-check after you run "spec-cleaner -i xxx.spec", which will quote such macros.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the common shared library detection mechanism (/sbin/ldconfig) will not find dependencies for it. That is, <tt>%go_requires</tt> itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will add '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages do not have header files. They are statically built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will add '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ===<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
== Packaging tricks for Go ==<br />
<br />
=== "tags" in go get ===<br />
<br />
Sometimes upstream e.g. gozmq told you to "go get -tags xxx $IMPORTPATH" to get a specific version , and they put files for all tags together in one repository. What's worse, newer tags like "zmq_4_x" needs files from older tags like "zmq_3_x" and "zmq_2_2" to build (Maybe that's why upstream didn't split files into different git branches). Plus the "*_test.go" files, they totally get us confused about which file can be deleted for the build of a specific version.<br />
<br />
So we can't simply deleted "zmq_3_x" files for "zmq_4_x" builds, and considering the "*_test.go" files, it'll be a total mess for us to use "%{?suse_version}" to delete files (illogic, changeable all the time). All in all, "go get -tags" is the perfect, most simple, and (maybe) only possible way.<br />
<br />
In this case, we need to manually "construct" a "go get" to replace %gobuild. As [[#Where will Golang find dependencies?]] shows, "go get" will try to find sources in $GOPATH before actually downloading online (the later will certainly break because OBS build VM doesn't have any network), it indicates that if we put sources at the right place (%goprep) and export the correct envrionment variables, "go get" is '''usuable''' on OBS. So we can change commands in specfiles like this:<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
%gobuild<br />
<br />
%install<br />
%goinstall<br />
<br />
to<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
# manual build<br />
export IMPORTPATH="github.com/alecthomas/gozmq"<br />
export BUILDFLAGS="-s -v -p 4 -x"<br />
export GOPATH=%{_builddir}/go:%{_libdir}/go/contrib<br />
%if 0%{?suse_version} >= 1230<br />
%if 0%{?suse_version} > 1315<br />
go get --tags zmq_4_x $BUILDFLAGS $IMPORTPATH<br />
%else<br />
go get --tags zmq_3_x $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
%else<br />
go get --tags zmq_2_1 $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
<br />
%install<br />
%goinstall<br />
<br />
=== $GOTOOLDIR is not rewritable ===<br />
<br />
Sometimes when building Go official packages e.g. go.tools, some binraries like "godoc" will force to install themselves into %{_libdir}/go/pkg/tool/linux_%{go_arch}, even if you have recontructed the %gobuild macro and exported GOTOOLDIR to %{_builddir}/go/pkg/tool/linux_%{go_arch}.<br />
<br />
This is intentional because Go upstream doesn't want official tools like godoc to be separately updated without the rest of go tools. But as go.tools is separately built from go main package, such decision will trigger "open /usr/lib64/go/pkg/tool/linux_amd64: Permission Denied" error on OBS.<br />
<br />
We patched go main package and provided a macro called "GOROOT_TARGET". If you:<br />
<br />
export GOROOT_TARGET="%{buildroot}%{_libdir}/go"<br />
<br />
before %gobuild, you can get this workaround.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/Installation&diff=68998Portal:Cinnamon/Installation2014-11-12T16:35:14Z<p>MargueriteSu: add installation video</p>
<hr />
<div>== One Click Install ==<br />
<br />
To install Cinnamon, click on the appropriate image:<br />
<br />
{{Version note|Factory|<br />
{{OCI|http://software.opensuse.org/ymp/X11:Cinnamon:Factory/openSUSE_Factory/patterns-openSUSE-cinnamon.ymp}}}}<br />
{{Version note|{{Current version}}|<br />
{{OCI|http://software.opensuse.org/ymp/X11:Cinnamon:Current/openSUSE_{{Current version}}/patterns-openSUSE-cinnamon.ymp}}}}<br />
{{Version note|{{Last version}}|<br />
{{OCI|http://software.opensuse.org/ymp/X11:Cinnamon:Current/openSUSE_{{Last version}}/patterns-openSUSE-cinnamon.ymp}}}}<br />
<!--<br />
{{Version note|Tumbleweed|<br />
{{OCI|http://software.opensuse.org/ymp/X11:Cinnamon:Factory/openSUSE_Tumbleweed/patterns-openSUSE-cinnamon.ymp}}}}--><br />
<br />
{{Info|Chrome, Epiphany, Opera, and Chromium users will have to download the .ymp file and then execute it locally by double clicking on it or use Firefox in order to directly execute the file.}}<br />
<br />
== zypper ==<br />
<br />
To install Cinnamon using zypper,<br />
<br />
sudo zypper ar http://download.opensuse.org/repositories/X11:/Cinnamon:/Current/openSUSE_13.2 Cinnamon<br />
sudo zypper ref Cinnamon<br />
sudo zypper in patterns-openSUSE-cinnamon<br />
<br />
== Manual selection way ==<br />
<br />
Add the repository mentioned above then check [[Portal:Cinnamon/Packages|Package Explanation]] to decide which package you want. Usually, '''<code>cinnamon</code>''', '''<code>cinnamon-session</code>''','''<code>muffin</code>''' will bring all nessary packages into installation.<br />
<br />
<div style="text-align:center;"><br />
<videoflash type="youtube">0Uy3YRU7Rbk</videoflash><br />
<br /><br /><br />
[https://www.youtube.com/watch?v=0Uy3YRU7Rbk&feature=youtu.be Install Cinnamon in a minimal X environment].<br />
</div></div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/Contact&diff=68954Portal:Cinnamon/Contact2014-11-11T09:18:26Z<p>MargueriteSu: </p>
<hr />
<div>{{Warning|Don't contact our individual team member unless you're told to. Let's be "default to open". Personal email can't help others.}}<br />
<br />
* You can meet us at: [irc://irc.freenode.net/opensuse-cinnamon #opensuse-cinnamon] channel on freenode. If nobody's there, goes to [irc://irc.freenode.net/opensuse-gnome #opensuse-gnome]...we may be visiting our neighbors.<br />
<br />
* You can open a bug report on openSUSE [https://bugzilla.novell.com/ bugzilla] and assign it to "i#marguerite.su" (replace # with @). But don't report bugs directly to that mail address.<br />
<br />
* You can write to #opensuse-factory mailing list (sorry we don't have our own yet)<br />
<br />
* You can yield at G+ opensuse community. I'll catch you :-)<br />
<br />
'''Please Don't do with an unconfirmed bug''':<br />
<br />
* Write on your own blog<br />
<br />
* Send to twitter or set it as your facebook status<br />
<br />
* Tell people around who actually can't help to scare them not to use us.<br />
<br />
[[Category:Cinnamon]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/Repos&diff=68953Portal:Cinnamon/Repos2014-11-11T09:16:34Z<p>MargueriteSu: </p>
<hr />
<div>{{Warning|Note: We will not maintain/keep packages for EOL releases. eg: when {{Last version}} reaches its EOL, all related repositories will be cleaned. You're encouraged to use with latest openSUSE.}}<br />
<br />
'''Stable release''': <br />
* [http://download.opensuse.org/repositories/X11:/Cinnamon:/Current/openSUSE_{{Current version}}/ openSUSE {{Current version}} with stable 2.4 release]<br />
* [http://download.opensuse.org/repositories/X11:/Cinnamon:/Current/openSUSE_{{Last version}}/ openSUSE {{Last version}} with stable 2.4 release]<br />
<br />
'''Develop/Unstable release''':<br />
* [http://download.opensuse.org/repositories/X11:/Cinnamon:/Factory/openSUSE_{{Current version}}/ openSUSE {{Current version}} with latest upstream release]<br />
* [http://download.opensuse.org/repositories/X11:/Cinnamon:/Factory/openSUSE_{{Last version}}/ openSUSE {{Last version}} with latest upstream release]<br />
<!--<br />
* [http://download.opensuse.org/repositories/X11:/Cinnamon:/Factory/openSUSE_Tumbleweed/ openSUSE Tumbleweed with latest upstream release]--><br />
* [http://download.opensuse.org/repositories/X11:/Cinnamon:/Factory/openSUSE_Factory/ openSUSE Factory with latest upstream release]<br />
<br />
'''Permission Placeholder''':<br />
<br />
[https://build.opensuse.org/project/show/X11:Cinnamon A place to gain maintainership], Just send a add_role SR against it.</div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/Repos&diff=68952Portal:Cinnamon/Repos2014-11-11T09:16:11Z<p>MargueriteSu: </p>
<hr />
<div>'''Latest''':<br />
<br />
{{Warning|Note: We will not maintain/keep packages for EOL releases. eg: when {{Last version}} reaches its EOL, all related repositories will be cleaned. You're encouraged to use with latest openSUSE.}}<br />
<br />
'''Stable release''': <br />
* [http://download.opensuse.org/repositories/X11:/Cinnamon:/Current/openSUSE_{{Current version}}/ openSUSE {{Current version}} with stable 2.4 release]<br />
* [http://download.opensuse.org/repositories/X11:/Cinnamon:/Current/openSUSE_{{Last version}}/ openSUSE {{Last version}} with stable 2.4 release]<br />
<br />
'''Develop/Unstable release''':<br />
* [http://download.opensuse.org/repositories/X11:/Cinnamon:/Factory/openSUSE_{{Current version}}/ openSUSE {{Current version}} with latest upstream release]<br />
* [http://download.opensuse.org/repositories/X11:/Cinnamon:/Factory/openSUSE_{{Last version}}/ openSUSE {{Last version}} with latest upstream release]<br />
<!--<br />
* [http://download.opensuse.org/repositories/X11:/Cinnamon:/Factory/openSUSE_Tumbleweed/ openSUSE Tumbleweed with latest upstream release]--><br />
* [http://download.opensuse.org/repositories/X11:/Cinnamon:/Factory/openSUSE_Factory/ openSUSE Factory with latest upstream release]<br />
<br />
'''Permission Placeholder''':<br />
<br />
[https://build.opensuse.org/project/show/X11:Cinnamon A place to gain maintainership], Just send a add_role SR against it.</div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/TODO&diff=68951Portal:Cinnamon/TODO2014-11-11T09:00:43Z<p>MargueriteSu: </p>
<hr />
<div>* Packaging list:<br />
** mdm-themes -- you know what it is<br />
** icon theme we selected (doesn't even start to select yet)<br />
** branding packages for mdm, cinnamon itself, gtk3 theme. <span style="color:orange">In progress</span><br />
* Spread the word and attract some users to be our '''testers'''.<br />
* Create an official "custom" to separate us from Mint in plain eye looking. We '''should''' be more eye-candy than the origin! which should include:<br />
** A wallpaper set (several images with ultra-high resolution support, find them on DeviantArt or hold an contest ourselves). We may not use official openSUSE wallpaper if it doesn't fit...with {{User|MargueriteSu}}'s design capability, we can create our own.<br />
** A gtk3 theme. To be forked from [http://numixproject.org Numix]. May provide dark/light variants.<br />
** [http://doublechou.deviantart.com/art/openSUSE-Cinnamon-411001257 A Cinnamon itself theme] like KDE plasma workspace theme. May provide dark/light variants.<br />
** An icon theme. Ask from users (forum/G+/IRC [irc://irc.freenode.net/opensuse-gnome #opensuse-gnome], just spread the word). Deviant is not reliable (some theme looks superb, but with only less than 50 icons, it even lacks of a default "folder" icon!), while gnome-icon-theme/mint-x-icons is also ugly.<br />
* <del>Final Goal: submit to openSUSE Factory and make it an official alternative desktop environment!</del> <span style="color:red">No goals setup, it's not officially supported upstream.</span> Before that we should:<br />
** Open bug reports against serveral dbus services/polkit policies we use and cooperate with our Security Team to have them audited.</div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/Help&diff=68950Portal:Cinnamon/Help2014-11-11T08:54:47Z<p>MargueriteSu: </p>
<hr />
<div>There're a few ways you can help us out:<br />
<br />
== Users ==<br />
<br />
* Use (of course)<br />
* Warm words to encourage us to keep going<br />
* Spread words to other users to form a cycle inside our big community. Let's just keep barking.<br />
* Engaging (To vote for new icon themes...to take photo and submit to our wallpaper contest maybe! to draw artworks/make themes for us...like this. You don't have to know how to code before helping us)<br />
* Testing (Install the ones from our devel repository).<br />
* Bug reporting (Assign to {{User|MargueriteSu}} directly or it'll be automatically assigned to Dimstar...which will be awkward...)<br />
* Watch this project to prevent it from being inactive again! Seriously, I have a more important responsiblity to hold, which is M17N the input methods thing...and My own desktop environment is actually KDE...so this one person job may ends someday really. You can apply some permissions like developers' do (see below, but don't touch around directly, fork a branch first)! Just in case if no one is still here, you can wait and hand the develop permission over to other capable hands who wish to help.<br />
<br />
== Developers/Packagers ==<br />
<br />
Submit a fix to our packages:<br />
<br />
Send your branch to '''X11:Cinnamon:Factory''' using BURP way.<br />
<br />
Or: To submit a new package that we forget to package:<br />
<br />
Send your package to '''X11:Cinnamon:Factory''' on Build Service.<br />
<br />
Or: Join us to fix those unbroken things (well, sometimes it does breaks!) to get a better user experience! <br />
<br />
Send an add_role request against '''X11:Cinnamon''' by clicking the [https://build.opensuse.org/project/show/X11:Cinnamon Request role addition] button out there. (<font color=red>NOT X11:Cinnamon:Factory</font> which is for development purpose only, no one is actually _in_ that <font color=red>sub-</font>project. errrr...I'm in, to receive bug/submit request notifications)</div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/Bugs&diff=68949Portal:Cinnamon/Bugs2014-11-11T08:50:25Z<p>MargueriteSu: </p>
<hr />
<div>== Known Issues ==<br />
<br />
See [[Portal:Cinnamon/Known_issues|Known Issues for openSUSE]]<br />
<br />
== How can I give you valuable bug reports? ==<br />
<br />
Feel Free to contact any of our developers on [irc://irc.freenode.net/opensuse-cinnamon #opensuse-cinnamon] or [https://bugzilla.opensuse.org/index.cgi openSUSE bugzilla]. But be aware, simply tell us what happened may be less help. Here're the progress we use to diagnose a problem:<br />
<br />
* If you can't login, can you run `cinnamon --replace` inside a working gnome-shell or KDE? what does the output say?<br />
<br />
{{Warning|running that command may black and freeze your X! Save your work before running it! and you must know how to switch to tty, init 3 && init 5 to get back!}}<br />
<br />
{{Warning|remember to `sudo systemctl stop NetworkManager` if you have any working network connection. Cinnamon will seek control of network, which conflicts with your working GNOME-shell(they both use nm-applet)...so don't give them any network both! Or you'll surely fail because cinnamon can't start with a running NetworkManager!}}<br />
<br />
* If you can run `cinnamon --replace` but still can't login using GDM or other stuff, can you give us some logs?<br />
<br />
:<p>First, login to tty, then switch back to gdm and login cinnamon (remember the &lt;time&gt;), if failed, switch back to tty again, run</p><br />
<br />
:<p><pre>su { journalctl --since &lt;time&gt; } > /home/<your username>/journal.log&#10;chown <your username>:users /home/<your username>/journal.log</pre></p><br />
<br />
:<p>We need that '''journal.log''' and '''.xsession-errors-:0''' inside your home directory.</p><br />
<br />
* If you can't start an application, can you run it from a terminal (inside /usr/bin, there're lots of stuff prefixed with "cinnamon-", that'll be what you need) and see the outputs? (Cinnamon used a lot of Python, so it's hard for us to find all the dependencies at build time. Python is a scripting language, it will not fail until code get run. Upstream has a very poor documentation about its `runtime` dependencies.)<br />
<br />
* If your cinnamon workspace is wrong (eg, some applets can't be loaded, some extensions can't be enabled), can you please press "<code>Meta</code> (the Win key) + <code>L</code>" to trigger Cinnamon Looking Glass and tell us the output under the '''Error''' tab?<br />
<br />
That's all.</div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/Known_issues&diff=68948Portal:Cinnamon/Known issues2014-11-11T08:42:23Z<p>MargueriteSu: </p>
<hr />
<div>{{Intro|This page keeps records for known issues about adopting Cinnamon to openSUSE. What will work and what will not, due to what. These issues are mostly occured because Cinnamon is a Linux Mint community project intead of a DE targeting all the distributions.'''Feel free to add some'''.}}<br />
<br />
* <del>on 1310, install Cinnamon may make GDM losing its icons.</del> <font color=red>fixed</font> forgot to run %icon_theme_cache_post to update icon caches<br />
<br />
* <del>on 1310, cinnamon-session can't be shown in GDM or get started.</del> <font color=red>fixed</font> added missing runtime dependencies.<br />
<br />
* <del>Nemo can't start on 1310.</del> <font color=red>fixed</font> It's because upstream (Linux Mint) uses a lower GNOME/GTK version than us openSUSE for almost every release, so upstream developers don't even be aware of the problems we met. <br />
<br />
* <del>muffin for openSUSE 12.3 will stay at a certain commit forever until openSUSE 12.3 formally reaches its EOL. Because Ubuntu 14.04 was released with GNOME 3.10, Linux Mint decided to bump its LTS support to it. So GNOME requirement is now limited to GNOME 3.10+. Meanwhile openSUSE 12.3 and Fedora 19 all ships GNOME 3.6-3.8. Then we have to stay at the commit without Hi-DPI support.</del> 12.3 EOL soon, remove the support<br />
<br />
* No bluetooth support for 13.1+. Because starting from GNOME 3.12, GNOME upstream decided to drop rfkill support in gnome-bluetooth, and reinvented the wheels in gnome-settings-daemon. But cinnamon upstream wouldn't care because Linux Mint still freezed at GNOME 3.8, even in its latest release.<br />
<br />
* "One or more applets can not be loaded". the one is bluetooth@cinnamon.org, because we didn't ship the unfunctional cinnamon-bluetooth package (actually the error is still there because we don't have gnome-bluetooth 3.8).<br />
<br />
[[Category:Cinnamon]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/Known_issues&diff=68947Portal:Cinnamon/Known issues2014-11-11T08:41:47Z<p>MargueriteSu: </p>
<hr />
<div>{{Intro|This page keeps records for known issues about adopting Cinnamon to openSUSE. What will work and what will not, due to what. These issues are mostly occured because Cinnamon is a Linux Mint community project intead of a DE targeting all the distributions.}}<br />
<br />
* <del>on 1310, install Cinnamon may make GDM losing its icons.</del> <font color=red>fixed</font> forgot to run %icon_theme_cache_post to update icon caches<br />
<br />
* <del>on 1310, cinnamon-session can't be shown in GDM or get started.</del> <font color=red>fixed</font> added missing runtime dependencies.<br />
<br />
* <del>Nemo can't start on 1310.</del> <font color=red>fixed</font> It's because upstream (Linux Mint) uses a lower GNOME/GTK version than us openSUSE for almost every release, so upstream developers don't even be aware of the problems we met. <br />
<br />
* <del>muffin for openSUSE 12.3 will stay at a certain commit forever until openSUSE 12.3 formally reaches its EOL. Because Ubuntu 14.04 was released with GNOME 3.10, Linux Mint decided to bump its LTS support to it. So GNOME requirement is now limited to GNOME 3.10+. Meanwhile openSUSE 12.3 and Fedora 19 all ships GNOME 3.6-3.8. Then we have to stay at the commit without Hi-DPI support.</del> 12.3 EOL soon, remove the support<br />
<br />
* No bluetooth support for 13.1+. Because starting from GNOME 3.12, GNOME upstream decided to drop rfkill support in gnome-bluetooth, and reinvented the wheels in gnome-settings-daemon. But cinnamon upstream wouldn't care because Linux Mint still freezed at GNOME 3.8, even in its latest release.<br />
<br />
* "One or more applets can not be loaded". the one is bluetooth@cinnamon.org, because we didn't ship the unfunctional cinnamon-bluetooth package (actually the error is still there because we don't have gnome-bluetooth 3.8).<br />
<br />
[[Category:Cinnamon]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/Packages&diff=68946Portal:Cinnamon/Packages2014-11-11T08:33:37Z<p>MargueriteSu: </p>
<hr />
<div>There are approximately 80 packages hosted on the repository; however, not all of them are needed:<br />
<br />
# <code>*-devel</code>, <code>*-debuginfo</code>, <code>*-debugsource</code> packages are not required by default. They are mostly needed to track issues and bugs.<br />
# Users who employ English as their sole desktop language do not need <code>*-lang</code> packages and <code>cinnamon-translations</code>. Installing these packages will require Cinnamon to be localized. <br />
# Manual installation of <code>typlib-1_0-*</code> packages is not required. If needed, they'll be automatically pulled in. The same applies to <code>lib*</code> packages.<br />
<br />
== Basic Information about Cinnamon packages: ==<br />
<br />
* <code>cinnamon</code> : Core package providing the desktop shell.<br />
<br />
* <code>cinnamon-session</code> : Package that enables the user to log in to Cinnamon.<br />
<br />
* <code>cinnamon-2d</code> : Package providing fallback mode with 2D acceleration. Intended for use on systems that are incapable of handling 3D acceleration. <br />
<br />
* <code>cinnamon-menu-editor</code> : Dummy package required by Cinnamon. It will be automatically pulled in and is not required to be installed manually. <br />
<br />
* <code>cinnamon-settings</code> : The central place to set your backgrounds, themes, icons...<br />
<br />
* <code>cinnamon-control-center</code> : Package Providing a Graphical User Interface for editing Cinnamon settings such as themes, icons, and fonts. <br />
<br />
* <code>cjs</code> : binaries for <code>libcjs0</code>, which is a dependency for Cinnamon to display its JavaScript applets, like the way <code>gjs</code> does in gnome-shell. This package is required in order to make Cinnamon functional.<br />
<br />
* <code>muffin</code> : the window manager of Cinnamon similar to Mutter for GNOME. It is an essential package. <br />
<br />
* <code>nemo</code> : File manager for Cinnamon. Installing Nemo is not essential for the shell to be functional, but without it cinnamon-session will fail.<br />
<br />
* <code>cinnamon-screensaver</code> : Screensaver for Cinnamon. <br />
<br />
* <code>cinnamon-settings-daemon</code> : Not required to be manually installed. It will be pulled in automatically and it's essential for Cinnamon. <br />
<br />
* <code>nemo-extensions</code> : Meta package that will pull in all <code>nemo-* </code>extensions. It is an optional package and will install multiple extensions. <br />
<br />
* <code>nemo-python</code> : Python bindings for <code>nemo</code>. Doesn't require manual installation.<br />
<br />
* <code>nemo-*</code> : Nemo extensions. Each package is named after its function. <br />
<br />
* <code>mdm</code> : the recommended simple login manager by Cinnamon upstream. Users are free to use Lightdm, XDM, GDM, or KDM instead.</div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/Installation&diff=68945Portal:Cinnamon/Installation2014-11-11T08:29:23Z<p>MargueriteSu: </p>
<hr />
<div>== One Click Install ==<br />
<br />
To install Cinnamon, click on the appropriate image:<br />
<br />
{{Version note|Factory|<br />
{{OCI|http://software.opensuse.org/ymp/X11:Cinnamon:Factory/openSUSE_Factory/patterns-openSUSE-cinnamon.ymp}}}}<br />
{{Version note|{{Current version}}|<br />
{{OCI|http://software.opensuse.org/ymp/X11:Cinnamon:Current/openSUSE_{{Current version}}/patterns-openSUSE-cinnamon.ymp}}}}<br />
{{Version note|{{Last version}}|<br />
{{OCI|http://software.opensuse.org/ymp/X11:Cinnamon:Current/openSUSE_{{Last version}}/patterns-openSUSE-cinnamon.ymp}}}}<br />
<!--<br />
{{Version note|Tumbleweed|<br />
{{OCI|http://software.opensuse.org/ymp/X11:Cinnamon:Factory/openSUSE_Tumbleweed/patterns-openSUSE-cinnamon.ymp}}}}--><br />
<br />
{{Info|Chrome, Epiphany, Opera, and Chromium users will have to download the .ymp file and then execute it locally by double clicking on it or use Firefox in order to directly execute the file.}}<br />
<br />
== zypper ==<br />
<br />
To install Cinnamon using zypper,<br />
<br />
sudo zypper ar http://download.opensuse.org/repositories/X11:/Cinnamon:/Current/openSUSE_13.2 Cinnamon<br />
sudo zypper ref Cinnamon<br />
sudo zypper in patterns-openSUSE-cinnamon<br />
<br />
== Manual selection way ==<br />
<br />
Add the repository mentioned above then check [[Portal:Cinnamon/Packages|Package Explanation]] to decide which package you want. Usually, '''<code>cinnamon</code>''', '''<code>cinnamon-session</code>''','''<code>muffin</code>''' will bring all nessary packages into installation.</div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/Installation&diff=68944Portal:Cinnamon/Installation2014-11-11T08:26:07Z<p>MargueriteSu: /* One Click Install */ update one click installs</p>
<hr />
<div>== One Click Install ==<br />
<br />
To install Cinnamon, click on the appropriate image:<br />
<br />
{{Version note|Factory|<br />
{{OCI|http://software.opensuse.org/ymp/X11:Cinnamon:Factory/openSUSE_Factory/patterns-openSUSE-cinnamon.ymp}}}}<br />
{{Version note|{{Current version}}|<br />
{{OCI|http://software.opensuse.org/ymp/X11:Cinnamon:Current/openSUSE_{{Current version}}/patterns-openSUSE-cinnamon.ymp}}}}<br />
{{Version note|{{Last version}}|<br />
{{OCI|http://software.opensuse.org/ymp/X11:Cinnamon:Current/openSUSE_{{Last version}}/patterns-openSUSE-cinnamon.ymp}}}}<br />
<!--<br />
{{Version note|Tumbleweed|<br />
{{OCI|http://software.opensuse.org/ymp/X11:Cinnamon:Factory/openSUSE_Tumbleweed/patterns-openSUSE-cinnamon.ymp}}}}--><br />
<br />
{{Info|Chrome, Epiphany, Opera, and Chromium users will have to download the .ymp file and then execute it locally by double clicking on it or use Firefox in order to directly execute the file.}}<br />
<br />
== zypper ==<br />
<br />
To install Cinnamon using zypper,<br />
<br />
sudo zypper ar http://download.opensuse.org/repositories/X11:/Cinnamon:/Factory/openSUSE_13.1 Cinnamon<br />
sudo zypper ref Cinnamon<br />
sudo zypper in -t pattern Cinnamon<br />
<br />
== Manual selection way ==<br />
<br />
Add the repository mentioned above then check [[Portal:Cinnamon/Packages|Package Explanation]] to decide which package you want.</div>MargueriteSuhttps://en.opensuse.org/index.php?title=Template:Last_version&diff=68940Template:Last version2014-11-10T20:47:31Z<p>MargueriteSu: last version is 13.1</p>
<hr />
<div>13.1<noinclude><br />
<br />
----<br />
This is just a number of the previous (last) openSUSE version that can be used in article sections where this is the only change that will happen with newly released version.<br />
<br />
For instance in a template [[Template:Version note]] used in some page this template will keep page automatically updated as soon as this template is updated. No need to change tens of pages all over the wiki.<br />
<br />
[[Category:Timeline templates]]<br />
[[it:Template:Versione precedente]]<br />
</noinclude></div>MargueriteSuhttps://en.opensuse.org/index.php?title=Template:Current_version&diff=68939Template:Current version2014-11-10T20:47:11Z<p>MargueriteSu: it's 13.2 now</p>
<hr />
<div>13.2<noinclude><br />
<br />
----<br />
This is just a number of the current openSUSE version that can be used in article sections where this is the only change that will happen with newly released version. <br />
<br />
For instance in a template [[Template:Version note]] used in some page this template will keep page automatically updated as soon as this template is updated. No need to change tens of pages all over the wiki. <br />
<br />
[[Category:Timeline templates]]<br />
[[it:Template:Versione corrente]]<br />
</noinclude></div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/Screenshots/5&diff=68938Portal:Cinnamon/Screenshots/52014-11-10T20:43:01Z<p>MargueriteSu: </p>
<hr />
<div>[[File:Cinnamon-desklets.png | center | alt=Cinnamon Desklets | Cinnamon Desklets | 200px]]<br />
[[Category:Cinnamon]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:GNOME_Cinnamon&diff=68937openSUSE:GNOME Cinnamon2014-11-10T20:41:14Z<p>MargueriteSu: request for deletion</p>
<hr />
<div><div style="width:100%; float:left;clear:left"><br />
{{Delete|The repositories and instruction here were altered. So no longer guides but misleads. Admins should consider deletion of this package and related pictures (cinnamon1.png ~ cinnamon10.png & cinnamon-screenshot.png & cinnamon-version.png)<br />
-- [[User:MargueriteSu|MargueriteSu]] ([[User talk:MargueriteSu|talk]]) 20:41, 10 November 2014 (UTC)<br />
}}<br />
{{Obsolete|It's for Cinnamon 1.6.0. Currently we have [[Portal:Cinnamon]]. This page is history and we didn't figure out an idea about how to do with it.}}<br />
<br />
{{Box-header|Cinnamon for openSUSE|{{FULLPAGENAME}}|}}<br />
[[Image:cinnamon-screenshot.png|thumb|right|250px|* [[Portal:12.1|openSUSE 12.1]] with GNOME:Cinnamon]]<br />
<br />
Cinnamon is a Linux desktop which provides advanced innovative features and a traditional user experience. The desktop layout is similar to Gnome 2. The underlying technology is forked from Gnome Shell.<br />
<br />
Cinnamon features traditional gnome-panel layout with the main-menu, systray, workspace indicator etc.<br />
<br />
GUI configuration tool is under development, till then dconf-editor or gnome-tweak-tool can be used to fine-tune Cinnamon. <br />
<br />
{{Box-footer|}}<br />
</div><br />
<br />
<!-- Article Tag templates --><br />
<br />
__TOC__<br />
<br />
== Supported openSUSE Platforms ==<br />
{{Point here|[[Image:Logo-gnome.png|48px]]|<br />
* openSUSE 12.1 + GNOME 3.4 - Cinnamon 1.6.0<br />
* openSUSE 12.2 + GNOME 3.4 - Cinnamon 1.6.0<br />
* openSUSE 12.2 + GNOME 3.6 - Cinnamon 1.6.0<br />
* openSUSE Tumbleweed - Cinnamon 1.6.0<br />
* openSUSE Factory - Development<br />
}}<br />
<br />
== Included packages ==<br />
* ''cinnamon'' – cinnamon desktop<br />
* ''muffin'' – cinnamon’s window manager<br />
{{Info|DEPRECATED on 1.1.3: cinnamon-settings}}<br />
{{Info|DEPRECATED on 1.2.0: cinnamon-extensions, cinnamon-extension-weather}}<br />
<br />
= Install Cinnamon =<br />
{{info|'''WARNING''' - Before you install Cinnamon, make sure you have a working GNOME3 installation, otherwise don't bother installing Cinnamon! This is mainly important for KDE/LXDE users! Users running GNOME3 can install directly.}}<br />
<br />
=== Cinnamon 1-Click Installer ===<br />
<br />
==== openSUSE 12.1 ====<br />
* '''Cinnamon''' - '''{{OCI|http://download.opensuse.org/repositories/GNOME:/Cinnamon/12.1/cinnamon.ymp}}'''<br />
<br />
==== openSUSE 12.2 ====<br />
* '''Cinnamon''' - '''{{OCI|http://download.opensuse.org/repositories/GNOME:/Cinnamon/12.2/cinnamon.ymp}}'''<br />
<br />
==== openSUSE Tumbleweed ====<br />
* '''Cinnamon''' - '''{{OCI|http://download.opensuse.org/repositories/GNOME:/Cinnamon/Tumbleweed/cinnamon.ymp}}'''<br />
<br />
==== openSUSE Factory ====<br />
* '''Cinnamon''' - '''{{OCI|http://download.opensuse.org/repositories/GNOME:/Cinnamon/Factory/cinnamon.ymp}}'''<br />
<br />
Once installation is complete, log out, Cinnamon should now be available as a session at the display manager (KDM/GDM), select Cinnamon session to log back into.<br />
<br />
Alternatively you can use the command line to install packages as mentioned below.<br />
<br />
=== Install from command line ===<br />
<br />
Set the repository according to your openSUSE version:<br />
<br />
==== For openSUSE 12.1 with GNOME 3.4 ====<br />
<br />
Run the following command (as root):<br />
<br />
{{Shell|zypper ar http://download.opensuse.org/repositories/X11:/Cinnamon:/GNOME34/12.1/X11:Cinnamon:GNOME34.repo}}<br />
<br />
==== For openSUSE 12.2 with GNOME 3.4 ====<br />
<br />
Run the following command (as root):<br />
<br />
{{Shell|zypper ar http://download.opensuse.org/repositories/X11:/Cinnamon:/GNOME34/12.2/X11:Cinnamon:GNOME34.repo}}<br />
<br />
==== For openSUSE Factory ====<br />
<br />
Run the following command (as root):<br />
<br />
{{Shell|zypper ar http://download.opensuse.org/repositories/X11:/Cinnamon:/Factory/Factory/X11:Cinnamon:Factory.repo}}<br />
<br />
After adding the repository accordingly your openSUSE version, refresh your zypper package database:<br />
{{Shell|# zypper refresh}}<br />
<br />
Finally, install the packages:<br />
{{Shell|# zypper in cinnamon}}<br />
<br />
Enjoy Cinnamon on openSUSE!<br />
<br />
----<br />
<br />
==Screenshots==<br />
{{Point here|[[Image:gallery.png|48px]]|<br />
<gallery><br />
File:cinnamon1.png|Desktop<br />
File:cinnamon2.png|Menu<br />
File:cinnamon3.png|Dock extension<br />
File:cinnamon4.png|Sysmon extension<br />
File:cinnamon5.png|Sysmon config<br />
File:cinnamon6.png|Volume control<br />
File:cinnamon7.png|Calendar<br />
File:cinnamon8.png|Hot corner<br />
File:cinnamon9.png|cinnamon-settings<br />
File:cinnamon10.png|Hot corner<br />
File:cinnamon11.png|Themes<br />
File:cinnamon12.png|Extensions<br />
</gallery><br />
<br />
}}<br />
----<br />
<br />
== Community Contributors ==<br />
{{Point here|[[Image:Icon-security.png|48px]]|<br />
<!--Please use alphabetic order by wiki username --><br />
* {{User|cyberorg}} - Initial packages<br />
* {{User|ketheriel}} - Cinnamon 1.2 packages<br />
* [http://susestudio.com/a/jMOVxa/opensuse-cinnamon Chrome Linux] - Base openSUSE 12.1 image with Cinnamon<br />
}}<br />
<br />
----<br />
<br />
==See also==<br />
<br />
*[https://github.com/linuxmint/Cinnamon/issues Issue tracker]<br />
*[https://github.com/linuxmint/Cinnamon Code]<br />
*[http://cinnamon.linuxmint.com/ Home page]<br />
<br />
[[Category:Cinnamon]]<br />
[[Category:12.1]]<br />
<br />
[[es:Cinnamon]]<br />
[[it:openSUSE:GNOME_Cinnamon]]<br />
[[ru:Cinnamon]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=File:Cinnamon-menu.png&diff=68934File:Cinnamon-menu.png2014-11-10T20:28:44Z<p>MargueriteSu: MargueriteSuuploaded a new version of &quot;File:Cinnamon-menu.png&quot;</p>
<hr />
<div></div>MargueriteSuhttps://en.opensuse.org/index.php?title=File:Cinnamon-desklets.png&diff=68933File:Cinnamon-desklets.png2014-11-10T20:26:09Z<p>MargueriteSu: </p>
<hr />
<div></div>MargueriteSuhttps://en.opensuse.org/index.php?title=File:Cinnamon-settings.png&diff=68932File:Cinnamon-settings.png2014-11-10T20:25:08Z<p>MargueriteSu: MargueriteSuuploaded a new version of &quot;File:Cinnamon-settings.png&quot;</p>
<hr />
<div></div>MargueriteSuhttps://en.opensuse.org/index.php?title=File:Cinnamon-nemo.png&diff=68931File:Cinnamon-nemo.png2014-11-10T20:24:51Z<p>MargueriteSu: MargueriteSuuploaded a new version of &quot;File:Cinnamon-nemo.png&quot;</p>
<hr />
<div></div>MargueriteSuhttps://en.opensuse.org/index.php?title=Portal:Cinnamon/Screenshots&diff=68930Portal:Cinnamon/Screenshots2014-11-10T20:23:12Z<p>MargueriteSu: </p>
<hr />
<div>==Cinnamon Desktop==<br />
<br />
[[File:Cinnamon-desktop.png | center | alt=Cinnamon desktop | Cinnamon desktop]]<br />
<br />
==Cinnamon Menu==<br />
<br />
[[File:Cinnamon-menu.png | center | alt=Cinnamon Menu | Cinnamon Menu]]<br />
<br />
==Cinnamon Nemo==<br />
<br />
[[File:Cinnamon-nemo.png | center | alt=Cinnamon Nemo | Cinnamon Nemo]]<br />
<br />
==Cinnamon Settings==<br />
<br />
[[File:Cinnamon-settings.png | center | alt=Cinnamon Settings | Cinnamon Settings]]<br />
<br />
==Cinnamon Desklets==<br />
<br />
[[File:Cinnamon-desklets.png | center | alt=Cinnamon Desklets | Cinnamon Desklets]]<br />
<br />
[[Category:Cinnamon]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=File:Cinnamon-desktop.png&diff=68929File:Cinnamon-desktop.png2014-11-10T20:20:59Z<p>MargueriteSu: MargueriteSuuploaded a new version of &quot;File:Cinnamon-desktop.png&quot;</p>
<hr />
<div></div>MargueriteSuhttps://en.opensuse.org/index.php?title=Category:13.2&diff=68796Category:13.22014-11-03T14:07:51Z<p>MargueriteSu: Created page with "{{Intro|This category page lists all specific pages about openSUSE 13.2.}}"</p>
<hr />
<div>{{Intro|This category page lists all specific pages about [[Portal:13.2|openSUSE 13.2]].}}</div>MargueriteSuhttps://en.opensuse.org/index.php?title=Archive:Features_13.2&diff=68795Archive:Features 13.22014-11-03T14:06:17Z<p>MargueriteSu: category and chinese version link</p>
<hr />
<div>{{Current_distribution_navbar|13.2}}<br />
<div style="text-align:justify;float:left;"><br />
<br />
==openSUSE 13.2 – Green Light to Freedom!==<br />
<gallery><br />
File:OpenSUSE 13.2 welcome.png|Welcome to 13.2!<br />
File:OpenSUSE 13.2 bootmenu.png|Bootmenu<br />
File:Desktop_selection_13.2.png|Desktop Selection 13.2<br />
File:Installing_13.2.png|Installation 13.2<br />
</gallery><br />
<br />
==More details on openSUSE 13.2==<br />
The following pages go into much detail on what is new in this openSUSE release. Too much information? Check out the [[Portal:13.2/Features|Feature highlights]] instead.<br />
<br />
__TOC__<br />
<br />
=== Under the hood ===<br />
This page is ready for 13.2 - looking for 13.1 to add your feature? You're late, but help is still welcome - go [[features_13.1|here]]. Screenshots go [[Screenshots_13.1|here]].<br />
<br />
dracut is an event driven initramfs infrastructure, and replaces in openSUSE 13.2 the old mkinitrd system. One advantage of dracut over mkinitrd is that the new project aims to have as little as possible hard-coded into the initramfs.<br />
<br />
=== Linux kernel 3.16 ===<br />
The system operates with the 3.16 kernel patch. Linux 3.16 comes with improvements for Nouveau the open source driver for NVIDIA cards as well as more features for Intel and AMD graphics. This new kernel improves the performance of Btrfs, as the default file system for the root partition, and XFS. <br />
==== Changes In Filesystems ====<br />
<br />
Btrfs is now the new default filesystem for root, and XFS for the /home directory. The use of Btrfs, together with Snapper (that leaps from 0.1.7 to 0.2.4) allows the user to recover the previous status of the system using snapshots. By default, Snapper will create a new snapshot before and after the update of the system (zypper). Also, this new version adds the ability to [http://snapper.io/2014/04/29/rollback.html boot right into a snapshot] to recover from corruption of important files on the system (like bash).<br />
<br />
=== Networking ===<br />
<br />
The old ifup mechanism was replaced by [https://en.opensuse.org/Portal:Wicked Wicked]. Wicked provides a new framework for network configuration and is a replacement for the `ifup` family of scripts. The Wicked framework uses a client/server and layered approach to the problem of network configuration. This allows Wicked to define standardized facilities for things like address configuration that are well integrated with the overall framework, and are layered on top of device specific services. Interprocess communication between the Wicked client and backend services such as the main Wicked daemon process is carried out via dbus.<br />
<br />
=== Persistent Live Media ===<br />
Live images are now persistent by default, so you can write the Live image to a USB stick, boot from it, store your data and install your favourite apps in it and carry it around as your own portable configured operating system.<br />
Inside the hood, they use BTRFS as the persistent filesystem, so the Live system is fast and stable from the get go.<br />
<br />
=== openSUSE technologies ===<br />
<br />
;YaST revamped installer<br />
<br />
The new openSUSE 13.2 installer comes with several changes targeted to make the installation process easier and more welcoming to new users. Those changes include:<br />
* New installation work flow. Up to 13.1 the installation was followed, after the first reboot, by the so called “2nd stage” phase, in which several additional settings needed to be configured. The new process is more straightforward removing the second stage. As soon as the basic installation is over, the system is ready to use.<br />
* You can even skip the last step and, instead of actually installing the system, export the configuration as a complete AutoYaST profile. <br />
* Better and smarter automatic proposals.<br />
* Less cluttered configuration options: some advanced configuration options (like LDAP user authentication, printer configuration,...) have been removed from the installer. These options are still available later after the system is installed and also through AutoYaST.<br />
* Brand new look and feel focused on usability.<br />
<br />
;YaST drop support for Grub Legacy<br />
<br />
As a first step to improve the robustness of one of the most challenging and relevant aspects of Linux installation and configuration, YaST will drop support for Grub Legacy in openSUSE 13.2 focusing on GRUB2, which was already the default and recommended option in openSUSE 13.1. Of course, Grub Legacy can still be manually installed but removing it from YaST will enable the developers to work on a more advanced approach to managing the bootloader in future openSUSE releases.<br />
<br />
;YaST other improvements<br />
<br />
Several parts of YaST have been improved and cleaned up after the automatic conversion from YCP language to Ruby shipped with 13.1. Compared to that version, the new YaST is:<br />
* Faster<br />
* More stable<br />
* Better integrated with systemd, btrfs and the other cutting edge technologies included in openSUSE 13.2.<br />
<br />
;YaST more accessible to developers<br />
<br />
Together with the abovementioned cleanup, the YaST team have put effort into adding developer's documentation and unit tests to YaST, with the goal to lower the barrier entry for technical contributors. In addition, to integrate all the new and not so new documentation, a new landing page targeted to developers is being developed (still a work in progress) at http://yast.github.io/. <br />
<br />
;Other features and changes<br />
<br />
PulseAudio was upgraded to version 5, which adds BlueZ 5 support (A2DP only), Reimplementation of the tunnel modules, Native log target support for systemd-journal, and many bug fixes. You can read more about it [http://www.freedesktop.org/wiki/Software/PulseAudio/Notes/5.0/ here]<br />
<br />
<gallery><br />
File:Welcome_13.2.png|Welcome 13.2<br />
File:Time_zone_13.2.png|Time Zone 13.2<br />
File:Desktop_selection_13.2.png|Desktop Selection 13.2<br />
File:Partitioner_13.2.png|Disk Preparation 13.2<br />
File:Install_overview_13.2.png|Installation Overview 13.2<br />
File:Installing_13.2.png|Installation 13.2<br />
</gallery><br />
<br />
=== Free Desktops ===<br />
openSUSE is unique among the major Linux distributions in delivering all major Free Desktops on an equal footing: officially developed and supported. These include [[#GNOME|GNOME]], [[#KDE|KDE]]’s Plasma Desktop (the default desktop) and Plasma Netbook, [[#Xfce|Xfce]], [[#LXDE|LXDE]], [[#Enlightenment|Enlightenment 19]] and [[#MATE|MATE]]. As usual, this release introduces some changes to the visuals through the new opensuse branding guidelines.<br />
<br />
=== KDE ===<br />
<center><br />
<gallery mode=packed heights=70><br />
File:Kde desktop 13.2.png | KDE Plasma Desktop 4.11<br />
File:Kde kontact 13.2.png | Kontact 4.14<br />
File:Kde widgets 13.2.png | Widgets<br />
File:Kde yast 02 13.2.png | YaST<br />
</gallery><br />
</center><br />
<br />
[[File:Kde file manager 13.2.png|thumb|right|250px|Default 13.2 Settings For Dolphin]]<br />
KDE Applications 4.14, dedicated to Volker Lanz, a long time KDE member who passed away last April, provides users a familiar look, feel and functionality. KDE Plasma Desktop is a good option for users transitioning from another OS.<br />
<br />
==== The Desktop ====<br />
OpenSUSE 13.2 ships with the latest latest stable version of the long-term support Plasma Workspace (4.11.12). Long-term support means no new features, but improved stability and bug fixes.<br />
<br />
Applications part of the Software Compilation have been updated to their latest stable releases (4.14.2; [https://www.kde.org/announcements/announce-4.14.2.php announcement]) as well.<br />
<br />
==== The Applications ====<br />
;Calligra<br />
<br />
The latest stable release of the Calligra office suite (2.8.5) is available, bringing new features and improvements across all the board.<br />
<br />
;KDE Telepathy<br />
<br />
openSUSE 13.2 ships the KDE Telepathy stack, an alternative set of applications to handle instant messaging, provided as an alternative to the venerable Kopete. Among the features offered by [http://blog.davidedmundson.co.uk/blog/ktp_0.9 the version shipped in the distribution] there are off-the-record (OTR) encryption for instant messaging, multi-protocol support (including popular IM services) and a set of applets for the Plasma Workspace to handle online status and messaging.<br />
<br />
;KDevelop 4.7<br />
<br />
For the users who are also developers, the distribution offers [https://www.kdevelop.org/news/kdevelop-470-released the latest version] of the fully featured IDE KDevelop, the last of the versions based on the 4.x KDE development platform. In addition to C++, there are plugins available which extend its support for additional languages such as PHP or Python.<br />
<br />
;KDE Frameworks 5 and Plasma 5<br />
<br />
KDE Frameworks 5, a series of development libraries on top of Qt 5 made by KDE, is present in its latest stable release (5.3.0). The libraries co-exist with the existing 4.x variants, allowing development of KF5-based applications within a stable 4.x based workspace.<br />
<br />
As a ''technical preview'', Plasma 5.1, the next generation workspace by KDE, is also present as an option for the brave users and tester willing to try it and report bugs to the developers.<br />
<br />
;Under the hood<br />
<br />
KDE applications requiring multimedia are now based on the 1.0 version of the GStreamer multimedia framework, allowing a noticeable reduction in dependencies. <br />
<br />
The Qt5 toolkit has also been updated to the latest version (5.3.2).<br />
<br />
=== GNOME ===<br />
<br />
openSUSE 13.2 comes with a much improved GNOME experience with GNOME 3.14.1 (openSUSE 13.1 had GNOME 3.10).<br />
<br />
<center><br />
<gallery mode=packed heights=70><br />
File:OS1320_GNOME-User-Menu.png | GNOME 3.14 desktop<br />
File:OS1320_SPG_Applications_Overview.png | Activities overview<br />
File:OS1320_SPG_Totem-Tears-Of-Steel.png | Video player<br />
File:OS1320_GNOME-Weather-LA.png | Weather App<br />
File:OS1320_GNOME_Software_Featured.png | Software App<br />
</gallery><br />
</center><br />
<br />
==== Interface improvements ====<br />
; Animations in the Shell and applications :<br />
The Shell feels more interactive now that it has gained pretty-but-subtle animations,<br />
for example, when switching to the applications overview and maximizing and restoring windows.<br />
Applications have also picked up support for animated transitions, and these are already<br />
implemented in core applications including clocks, weather, maps among others.<br />
<br />
; Perfect HiDPI screens support:<br />
GNOME 3.14 comes with perfect HiDPI support so that the desktop and all core GNOME applications<br />
look pretty on high-definition screens.<br />
<br />
; Support for captive portals when connecting to wifi:<br />
When connecting to a WiFi connection that requires you to log-in through a web-page,<br />
e.g., at airports, GNOME now automatically launches the log-in page in a browser as soon<br />
as the connection is established.<br />
<br />
; Configurable Network Sharing:<br />
GNOME now remembers which networks you want to enable sharing your personal files, media and screen<br />
on and therefore is completely privacy respecting. Additionally, sharing can be controlled and<br />
configured from ''Settings''.<br />
<br />
; Much improved searching in GNOME-Shell:<br />
Many more GNOME-Shell search providers (clocks, software, calculator...) make searching from the shell<br />
much more user-friendly and effective. You can, in addition to searching for files and documents, also<br />
search for Notes, open terminals, current time around the world by city names and so on.<br />
Typing in arithmetic operations in the search-bar gives you the result for the calculation straight on<br />
the shell overview.<br />
<br />
; Improved Geolocation support:<br />
Geolocation support in GNOME has been vastly improved, with many applications making use of this improved<br />
support. Thus, clocks, weather, maps and ''Date and Time Settings'' all benefit from being geolocation enabled,<br />
showing appropriate information based on you current location. E.g., weather defaults to showing the weather<br />
at your current place when launched after geolocation is enabled in ''Settings''. For the privacy <br />
concerned, ''Settings'' provides a way to toggle geolocation support on/off across all applications.<br />
<br />
; App-folders in GNOME Shell Application Overview:<br />
To reduce cluttering in the Application Overview, GNOME Shell now comes with ''Sundry'' and ''Utilties''<br />
applications packed in respective app-folders, showing these applications only when the app-folder is<br />
clicked on.<br />
In an openSUSE touch, the YaST modules come in their own app-folder now. This makes it easy to access<br />
any YaST module straight from the Shell without the added overhead of cluttering the overview.<br />
<br />
; Touch-screen gestures now supported:<br />
GNOME shell has gained full support for touch-screens, even enabling several utility multi-touch gestures<br />
for convenient switching to application overview, switching workspaces, and others.<br />
Indeed, this has allowed, for the first time, the notifications bar to be accessible by touch,<br />
mapping it to the swipe-up gesture.<br />
<br />
==== GNOME Applications ====<br />
; GNOME Maps gained support for route planning:<br />
Available as a ''preview'' application in openSUSE 13.1, ''Maps'' has stabilized and now comes<br />
with a host of advanced features. Prime among them is the support for route planning which<br />
is implemented using the open-source GraphHopper library.<br />
<br />
; GNOME Software, the new way of application management:<br />
Because the regular user is not interested in 'packages', which are a technicality,<br />
but rather in Applications, ''Software'' provides the Appstore featuring just applications.<br />
Using AppStream metadata, as published in the repository metadata, ''Software'' brings a<br />
much desired convenience to application management on GNOME, making it easy to find, <br />
install and update applications.<br />
<br />
; Google Account support for GNOME Photos:<br />
In addition to photos on your local computer, ''Photos'' can now also access photos on your<br />
Google/Picasa account.<br />
In addition, sharing to home media servers is also supported via DLNA.<br />
<br />
; Playlist support in GNOME Music:<br />
''Music'' gained the long awaited playlist support and is able to play music from remote systems (using the search capability).<br />
It is now the default music application on openSUSE 13.2 GNOME, and comes with a rich list of interface improvements<br />
since the version in the previous release.<br />
<br />
; All new Videos interface:<br />
Videos (Totem) was completely redesigned in the 3.12 cycle, making it more of a match to the GNOME3 application design<br />
guidelines and also picking up the ability to stream online videos from several pre-configured channels.<br />
The navigation toolbar now is overlaid on the actual video playback area and hides automatically when not in use, thus<br />
making the application interface uncluttered and allocating maximum screen space for the playing video. <br />
Beyond the (great!) new look, it still uses the trusty gstreamer library for smooth beautiful playback.<br />
<br />
; Modern interface for Document-viewer:<br />
Evince, the document viewer, comes in a vastly redesigned interface with a header bar that reduces vertical<br />
space usage, ensuring that it is your document that takes up maximum screen real-estate and not the application bezel.<br />
It also comes with support for pinch-to zoom gesture support on the touch-screen.<br />
<br />
; Polari -- A modern IRC client:<br />
Polari, a sleek, modern IRC client, replaces XChat as the default IRC application. For XChat aficionados, it is<br />
still available for install from the default repositories. <br />
<br />
; Other improvements:<br />
Several applications have ratcheted up significant improvements since the last release.<br />
* Boxes has gained support for snapshots<br />
* Documents now provides a way to delete selected documents<br />
* Meld, the file/directory diff-viewer gets gtk-3 interface<br />
* GEdit has a brand new interface with a pop-over based file open dialog<br />
* Bluetooth setting has been redesigned to make it easier to configure<br />
* Lots of visual refinement has gone into the desktop and applications to provide a more consistent, stylistic view across the board<br />
<br />
==== GNOME Infrastructure / internals ====<br />
* Improved support for MultiTouch input devices, including gesture support<br />
* Wayland support greatly inproved, including Drag'n'Drop, Touch, and GNOME Classic Mode<br />
* Geolocation: In addition to wifi-geolocation, GNOME now use Mozilla Location Service for 3G-geolocation and geoip. This means increased accuracy, especially in the long term.<br />
<br />
=== Xfce ===<br />
<br />
openSUSE 13.2 will ship with the same Xfce version as its predecessor, as XFCE 4.12 isn’t out yet. But worry not, the Xfce team has been working diligently so there have been under the hood changes to allow better integration with systemd and upower >= 0.99. Also, to mention a couple of most user-visible changes, there are new version so of gigolo, the midori web browser (with a much improved adblock functionality and spell checking) and a fully redesigned Parole. xfburn 0.5.2 now supports Blu-Ray and large files through ISO9660 level 3. More noticeable will be the changes to the core XFCE4 plugins:<br />
<br />
* xfce4-clipman-plugin 1.2.6 brings a new QR-code generator and the ability to skip actions via a keyboard shortcut<br />
* xfce4-timer-plugin 1.6.0 has the ability to rerun a timer from the alarm notification<br />
* Whisker Menu 1.4.0 introduces a new command to launch menu editor and to switch users, support for custom menu files, drag and drop for launchers to panel or desktop, added search actions, the ability to browse commands and to hide them, as well as hiding category and launcher icons.<br />
* xfce4-power-manager 1.4.0 brings a completely revamped and vastly simplified UI with a new panel plugin to show the status of batteries, switch to presentation mode<br />
* xfce4-taskmanager 1.0.1 features UI fixes and bugfixes<br />
* xfce4-terminal 0.6.3 has improved URL matching, a new light solarized color scheme and the usual bugfixes<br />
<br />
openSUSE 13.2 will also introduce a new custom theme for the notification daemon (xfce4-notifyd).<br />
<br />
=== LXDE ===<br />
[[File:13.2_-_LXDE_-_PCManFM.jpg|thumb|right|250px|PCManFM featuring Breadcrumb, Dual Pane and Menu Editor]]<br />
Who said that [[Portal:LXDE | LXDE]] was stalled? It has recently reached version 0.99.0 and is now on the way to version 1.0. However, openSUSE 13.2 ships '''LXDE 0.5.5''', with its packages updated to the latest available at package freeze time. Most of its core components and applications have had new version releases bringing '''lots of bug fixing''', '''new features''' and '''improvements'''. For example,<br />
<br />
* '''PCManFM 1.2.2''', the file manager, has now '''dual-pane''' support; the ability to control the status bar visibility and to hide elements in the toolbar, or the toolbar itself; new options to open automounted media in a new tab, to open folders from desktop in a new window and to copy path(s); the path bar can use buttons instead of a location text field allowing '''breadcrumb navigation''' of the filesystem. As an extra bonus, '''basic menu editing functions''' are present if you select Applications in the Places panel.<br />
* '''LibFM 1.2.2''' is one of the LXDE core libraries and PCManFM releases are closely tied to it. It has gained many features that are reflected in other components. It has also received enhancements and an extensive bug fixing, so all of its clients are now more stable than ever.<br />
* '''menu-cache 0.7.0''', another core component used to generate a cache version of the application menu, has been improved to be faster and more complete than it has ever been before.<br />
[[File:13.2_-_LXDE_-_Run_dialog.jpg|thumb|right|250px|Run Dialog]]<br />
* '''LXPanel 0.7.1''' can now close all windows within a group; has gained basic multi-monitor support, a new keyboard layout toggle dialog and supports adding accelerators to the main menu. There are also the '''new plug-ins 'launchtaskbar'''' (which combines functionality from 'launchbar' and 'taskbar') and ''''weather''''. Dragging of task buttons in the launchtaskbar has been improved and it is now allows the dragging of applications in the menu so they can be dropped elsewhere (the only supported case seems to be drop them onto PCManFM/desktop now). Last but not least, you can customize the panel to your liking thanks to the new support for custom <code>gtkrc</code> files, a.k.a. '''[http://wiki.lxde.org/en/LXPanel_Theming theming support]'''.<br />
* '''LXRandR 0.3.0''' GUI frontend for <code>xranrd</code> has gained '''new monitor positioning options''', a '''confirmation dialog''' on mode(s) change, and improved '''automatic monitors detection'''.<br />
* '''LXCC''', LXDE Control Center, includes now the previously missing translations.<br />
* and much more...<br />
<br />
On top of this, the '''desktop has moved from Clearlooks GTK theme to Adwaita'''. This gives to the desktop a more uniform appearance when using both GNOME and LXDE applications at the same time. The theming issues present in 13.1 are now solved and you won't have any problems to select icon, GTK or mouse cursor themes. '''Openbox''' presents a '''new theme''' that matches with Adwaita too, and, finally, the panel has dropped that old black background image and it now uses a color that fits better with the overall appearance of the desktop. Not a big revolution but hopefully a step forward. If you want a better integration of Qt applications, just run <code>qtconfig</code> and select ''GTK+'' from the ''GUI Style'' drop down list.<br />
<br />
Other changes present in openSUSE 13.2 are:<br />
<br />
* '''Leafpad''' is the default editor for basic editions and Beaver has been dropped (but is still available if you want it) in favor of '''Geany''' for advanced task,<br />
* inclusion of '''gcolor2''' color picker so you don't have to open a graphics program just to select a color,<br />
* '''xfce4-screenshooter''' replaces '''mtPaint''' for screen capture tasks, allowing more options and leaving mtPaint for digital photos manipulation.<br />
<br />
[[File:13.2_-_LXDE_-_Customized_LXPanel.png|thumb|right|250px|Customized LXPanel]]<br />
Third party applications that complete the desktop have also been updated: '''Galculator''' 2.1.3, '''Parcellite''' 1.1.9, '''Viewnior''' 1.4, '''Xarchiver''' 0.5.4 (that now supports test/verify archives in addition to xz/tar.xz and RAR 5 file formats), ...<br />
<br />
Want more? Even though it is not an officially supported repository, X11:lxde provide the latest available versions of the desktop components and bug fixes for them. Visit the [[LXDE repositories]] wiki page to learn how to add this repository to your system.<br />
<br />
Want even more? If you're a brave user, '''LXQt''', the fusion of LXDE and Razor-qt projects and future replacement for LXDE written using Qt, is available in our repositories. Keep in mind that LXQt is in an early stage of development (version 0.8 has just been published) and still lacks features and maturity compared with LXDE. Again, this is not an officially supported repository.<br />
<br />
In short, this could be one of the best openSUSE LXDE releases of all the times. '''Try it!'''<br />
<br />
===MATE===<br />
After GNOME 2.x passed the torch to GNOME 3, GNOME 2.x environment was forked and now it’s called [http://mate-desktop.org/ MATE Desktop Environment]. The MATE desktop is now officially available under openSUSE 13.2 with MATE version 1.8.1, the latest stable release. It provides an intuitive and attractive desktop environment using traditional metaphors<br />
for Linux and other Unix-like operating systems.<br />
<br />
Applications<br />
* '''Mozo (1.8.0)''' is MATE Desktop menu editor, using the freedesktop.org menu specification.<br />
* '''Caja (1.8.2)''' is the official file manager for the MATE desktop. It allows to browse directories, preview files and launch applications associated with them. It works on local and remote filesystems.<br />
* '''Marco (1.8.2)''' is a small window manager, using GTK+ to do everything. It is developed mainly for the MATE Desktop.<br />
* '''Pluma (1.8.1)''' is a small, but powerful text editor. It has most standard text editor functions and fully supports international text in Unicode. Advanced features include syntax highlighting and automatic indentation of source code, printing and editing of multiple documents in one window. plumais extensible through a plugin system, which currently includes support for spell checking, comparing files, viewing CVS ChangeLogs, and adjusting indentation levels.<br />
* '''Eye of MATE (1.8.1)''' is a simple graphics viewer for the MATE Desktop which uses the gdk-pixbuf library. It can deal with large images, and zoom and scroll with constant memory usage. Its goals are simplicity and standards compliance.<br />
* '''Atril (1.8.1)''' is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.<br />
* '''Engrampa (1.8.1)''' is an archive manager. This means that you can create and modify archives; view the content of an archive; view and modify a file contained in the archive; extract files from the archive.<br />
* '''MATE control center (1.8.3)''' is MATE's main interface for configuration of various aspects of your desktop.<br />
<br />
The objective, for openSUSE, is to provide the same experience users had when they used GNOME under openSUSE 11.4, with the '''main-menu''' and the '''Sonar''' theme.<br />
<br />
=== Enlightenment ===<br />
;Packaging Changes<br />
The enlightenment packaging sees some major changes since openSUSE 13.1, Most notably we have updated to enlightenment e19 which has resulted in some packaging changes as the old package was called e17. The new package is called enlightenment with the old enlightenment package being renamed to e16. As in some minor e17 features have been removed in the creation of e19 enlightenment e17 is still available in the e17 package<br />
<br />
{| class="wikitable"<br />
|-<br />
! Package Name !! Enlightenment version<br />
|-<br />
| enlightenment || ''e19''<br />
|-<br />
| e17|| ''e17''<br />
|-<br />
| e16|| ''e16''<br />
|}<br />
;New Features<br />
* New Dark and Light themes<br />
* New Dock and Tiling profiles<br />
* Package kit module integrated with YaST<br />
* Live previews in pager<br />
* Much improved taskbar (IBar)<br />
* Music Control module<br />
<br />
;Terminology<br />
WE are shipping terminology 0.6.1 as part of openSUSE 13.2 which also contains many new features with, Splits, Tabs and More complete configuration dialogs<br />
<br />
=== Graphics and multimedia ===<br />
* VDR - The Video Disk Recorder is now version 2 (prior it was 1.6) which fully supports HDTV and cards for DVB-S2 and DVB-T2.<br />
<br />
== Scientific ==<br />
<center><br />
<gallery mode=packed heights=80><br />
File:OS1320_Science_Stellarium.png | Stellarium showing the night sky<br />
File:OS1320_Science_Scilab.png | Scilab in action<br />
File:OS1320_Science_Veusz.png | Veusz, a GUI plotting software<br />
OS1320_Science_wxMaxima.png | wxMaxima running Maxima<br />
</gallery><br />
</center><br />
<br />
===GNU Radio===<br />
[http://gnuradio.org/redmine/projects/gnuradio/wiki GNU Radio] (latest upstream version 3.7.5) is a free software development toolkit that provides signal processing blocks to implement software-defined radios and signal processing systems. It can be used with external RF hardware to create software-defined radios, or without hardware in a simulation-like environment. It is widely used in hobbyist, academic, and commercial environments to support both wireless communications research and real-world radio systems.<br />
<br />
===Scilab===<br />
For the first time, [http://www.scilab.org/ Scilab] (latest upstream version 5.5.1) , the MATLAB-compatible numerical computation application, is available from the default repository. See the news item [http://opensusescience.wordpress.com/2014/06/27/scilab-packages-for-opensuse/ here] for more details.<br />
<br />
===Packages for high-energy physics computation===<br />
A number of applications and libraries very commonly used for high-energy particle physics computation and simulation has been added to the default openSUSE 13.2 repository (these were available for openSUSE 13.1 and earlier through the addon science repository). These include:<br />
* [http://home.thep.lu.se/~torbjorn/Pythia.html Pythia] (8.186): A widely used event generator for collisions at high energies between elementary particles<br />
* [https://sherpa.hepforge.org/trac/wiki SHERPA-MC] (2.1.1): A Monte Carlo event generator for the Simulation of High-Energy Reactions of PArticles<br />
* [http://rivet.hepforge.org/ Rivet] (2.1.2): A toolkit for validation of Monte Carlo event generators<br />
* [http://yoda.hepforge.org/ YODA] (1.2.1): A lightweight common system for MC event generator validation analyses<br />
* [http://hepmc.hepforge.org/ HepMC] (2.06.09): An object oriented event record written in C++ for High Energy Physics Monte Carlo Generators<br />
* [http://fastjet.fr/ FastJet] (3.0.6): Jet finding in pp and e+e- collisions<br />
* [http://herwig.hepforge.org/ Herwig++] (2.7.1): An object oriented particle physics event generator, written in C++<br />
* [http://lhapdf.hepforge.org/ LHAPDF] (6.1.4): A unified and easy to use interface to modern PDF sets<br />
* [http://rk.hepforge.org/ Rk] (1.5): A C++ library implementation of several basic geometric entities and transformations for relativistic kinematics<br />
* [http://cadabra.phi-sci.com/ Cadabra] (1.33): Computer algebra system (CAS) designed specifically for the solution of problems encountered in field theory<br />
<br />
===Armadillo===<br />
[http://arma.sf.net Armadillo], a popular linear algebra library in C++ was updated to version 4.450.4, a major feature upgrade to version 3.930.3 available with openSUSE 13.1.<br />
<br />
===MathGL===<br />
[http://mathgl.sourceforge.net/doc_en/Main.html MathGL] has been updated to version 2.3 (2.1 in openSUSE:13.1).<br />
<br />
===Maxima and wxMaxima===<br />
The symbolic computation application [http://maxima.sf.net Maxima] has been updated to the latest upstream version 5.34.1 (5.31.3 in openSUSE:13.1).<br />
The wxWidgets-based frontend to maxima, [https://github.com/andrejv/wxmaxima wxMaxima], was updated to version 14.09.0 (13.04.2 in openSUSE 13.1). <br />
<br />
===Octave===<br />
GNU [https://gnu.org/software/octave/ Octave], a high-level interpreted language primarily intended for numerical computations, has been updated to version 3.8.2 (3.6.4 in openSUSE 13.1). This is a major feature upgrade, in particular, adding a new (as yet experimental) GUI support and direct OpenGL support among many other new features. See [https://gnu.org/software/octave/NEWS-3.8.html here] for a summary.<br />
<br />
===PLplot===<br />
The plotting library [http://plplot.sf.net PLplot] with bindings for a large number of programming languages has been updated to version 5.10.0 (5.9.9 in openSUSE 13.1).<br />
<br />
===Stellarium===<br />
The popular planetarium simulator [http://stellarium.sf.net Stellarium] sees a major update to version 0.13.0 (0.12.4 in openSUSE 13.1). It is now built upon the QT5 toolkit and includes a bunch of new features.<br />
<br />
===Texmaker===<br />
[http://www.xm1math.net/texmaker/ Texmaker] was updated to version 4.3 (4.0.4 in openSUSE:13.1). This update adds scripting support, a new wizard for beamer presentations, LuaLaTeX support, and a visual diff view for the source viewer.<br />
<br />
===Veusz===<br />
The GUI plotting software [http://home.gna.org/veusz/ Veusz] has been updated to version 1.21.1 (1.18 in openSUSE 13.1). Apart from a number of new features and bug-fixes, it is now available in both python 2 and python 3 flavours (try python3-veusz) from the default repository.<br />
<br />
===Vtk and Paraview===<br />
The large data analysis and visualization applications [http://www.vtk.org/ Vtk] and [http://www.paraview.org/ Paraview] have been updated to their latest upstream versions 6.1.0 (6.0.0 in 13.1) and 4.2.0 (4.0.1 in 13.1) respectively. VTK 6.1.0 fixes bugs and adds features on top of the more modular code structure of version 6.0. With about 170 issues resolved, the updated Paraview includes several bug fixes and feature enhancements, notably:<br />
* A Redesigned Color Map Editor panel<br />
* Enhancements to Find Data dialog<br />
* Enhancements for interactions with Plots<br />
* Support for Python-based views<br />
* Updates to ParaViewWeb<br />
<br />
== Financial ==<br />
=== GNU Cash ===<br />
GNU Cash 2.6 comes with [http://gnucash.org/2.6-release-tour.phtml many new features] most notably:<br />
* Jplot support to give graphical reports a more professional look<br />
* Preconfigured report management system<br />
* Export reports directly to PDF<br />
* Account colors to help with organization<br />
<br />
== Web Stack ==<br />
=== MySQL ===<br />
<br />
=== httpd ===<br />
<br />
=== Cloud ===<br />
<br />
== Development tools, IDEs, toolchain ==<br />
=== IDEs and compilers ===<br />
;KDevelop 4.7<br />
<br />
For the users who are also developers, the distribution offers [https://www.kdevelop.org/news/kdevelop-470-released the latest version] of the fully featured IDE KDevelop, the last of the versions based on the 4.x KDE development platform. In addition to C++, there are plugins available which extend its support for additional languages such as PHP or Python.<br />
<br />
;Anjuta 3.14.0<br />
<br />
openSUSE 13.2 also comes with the latest stable version 3.14.0 of the powerful and feature-packed IDE [http://anjuta.org/ Anjuta]. Featuring support for an incredible number of programming languages (natively supporting C/C++, Python, Java, JavaScript, Vala...) Anjuta also comes with seamless integration with GLADE, thus providing an easy WYSIWYG GTK+/GNOME UI development. The updated version comes with several important bug-fixes compared to the one shipped with the previous openSUSE release, viz., Anjuta 3.10.0.<br />
<br />
=== Languages and Libraries ===<br />
<br />
;KDE Frameworks<br />
KDE Frameworks 5, a series of development libraries on top of Qt 5 made by KDE, is present in its latest stable release (5.3.0). The libraries co-exist with the existing 4.x variants, allowing development of KF5-based applications within a stable 4.x based workspace.<br />
<br />
;Scripting Languages<br />
Ruby packaging is now even easier. Need JRuby? Want Rubinius? No problem. We can do it. Not only Ruby has been updated (2.1.3), but also Python (2.7.8 and 3.4.1), PHP (5.6.1), Perl (5.20) and many others.<br />
<br />
== Security ==<br />
<br />
AppArmor 2.9 contains the new python-based tools developed during GSoC 2013, including the new aa-mergeprof to merge multiple sets of profiles, and aa-cleanprof to remove superfluous rules from a profile.<br />
<br />
The mod_apparmor apache module now uses the vhost name as a default hat name, if no other name is defined (see mod_apparmor(8) for details).<br />
<br />
AppArmor 2.9 also contains some new rule types to mediate sockets, ptrace, signals and dbus. Note that those rules are not yet supported by the openSUSE kernel and dbus, so they're just ignored.<br />
<br />
Of course the new version also contains the usual bunch of profile updates, bugfixes etc.<br />
<br />
[[Category:13.2]]<br />
[[zh:Features_13.2]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=SDB:KDE_Plasma_5&diff=68794SDB:KDE Plasma 52014-11-03T14:05:47Z<p>MargueriteSu: chinese</p>
<hr />
<div>__TOC__<br />
<br />
== What is Plasma 5 ? ==<br />
<br />
Plasma 5 is the new version of the workspace (also referred as "the desktop environment") by KDE, which replaces the old Plasma Workspace 4.x. It was built from the ground up to make use of the new features from the Qt libraries (version 5) and the KDE Frameworks 5 development platform. <br />
<br />
Among the new features brought from this version:<br />
<br />
* '''New, cleaned up and modernized visuals''': Plasma 5 offers a new consistent, high-contrast, visual theme, called ''Breeze'', in both light and dark variants. The theme is complemented with a new widget style and brand new icons.<br />
* '''Improved performance thanks to an updated graphic stack''': the user interface is rendered through OpenGL and OpenGL ES, allowing to offload computationally-intensive rendering tasks.<br />
* '''Better support for high DPI displays''': many parts of the UI now take into account the physical size of the display, leading to improved visuals on high density displays like Retina.<br />
* '''Improved user interface''': Widgets have been extensively reworked and a new set of UI design guidelines has been written, yielding improved usability and easier feature discoverability.<br />
<br />
== Installing Plasma 5 on openSUSE ==<br />
<br />
'''Notice''': The installation of Plasma 5 ''conflicts'' with the 4.x workspace. This means that you can install only one at a time (installing one will remove the other, and vice versa). Configuration will not be affected by this change: you will not lose your existing 4.x settings when moving to Plasma 5, which ensures you can go back without issues, should you want to.<br />
<br />
Since, and including openSUSE 13.2, for installing Plasma5 essentials, it is enough to install '''plasma5-session''' package. Alternatively, there is '''patterns-openSUSE-plasma5_basis''' pattern, for those that do not have KDE 4 already installed (pattern includes basic applications from KDE SC 4.x; it will be extended with KF5 counterparts as soon they have a release).<br />
<br />
<br />
=== Stable releases ===<br />
<br />
Stable releases versions reside in the KDE:Frameworks5 repository. This includes everything that has seen an official release from KDE, including, but not limited to:<br />
<br />
* The KDE Frameworks 5 libraries<br />
* Plasma 5<br />
* The SDDM display manager<br />
* Any KF5-based applications that have seen a release<br />
<br />
=== Unstable development snapshots ===<br />
<br />
The KDE:Unstable:Frameworks offers frequent snapshots from the KDE source code repository. In addition to the packages present in KDE:Frameworks5, there are unofficial snapshots of yet-unreleased applications that have been ported to the KDE Frameworks 5 libraries.<br />
<br />
Given the '''extreme''' speed of development, it must be noted that this repository is intended for '''advanced users only''' who also want to test and report bugs to KDE upstream, or to participate in the development.<br />
<br />
== User-visible changes and caveats ==<br />
<br />
=== System tray icons for applications such as Skype no longer show ===<br />
<br />
Plasma 5 has dropped the support for the legacy system tray protocol, also known as XEmbed. KDE software is unaffected as it uses the new Status Notifier protocol, but other applications may not appear anymore. <br />
<br />
* '''Qt4 applications (includes Skype)''' - Install the ''sni-qt'' package and logout. Upon the next login Qt 4 applications will show up in the system tray. As Skype is a 32bit application, you will have to install ''sni-qt-32bit'' as well if you are on a 64bit system. <br />
* '''Other applications''' - Legacy applications that do not belong to the above categories need a different adjustment. See [http://blog.martin-graesslin.com/blog/2014/06/where-are-my-systray-icons/ this blog post] for possible solutions.<br />
<br />
=== Starting programs on login ===<br />
<br />
The startup procedure of Plasma 5 has changed slightly compared to the 4.x workspace. In most cases everything should work out of the box, however some corner cases may need slight changes to work properly.<br />
<br />
==== Applications ====<br />
<br />
Use the autostart control panel in System Settings to configure programs to be started on login. In case you want to do the procedure manually, copy the application's .desktop file (e.g. "konsole.desktop") to ~/.config/autostart.<br />
<br />
==== Scripts ====<br />
<br />
Scripts are no longer executed upon login. This regression will be probably fixed in newer releases of Plasma 5, however a workaround exists to allow running them on login. <br />
Create a .desktop file for your application (example: "ssh-add.desktop") in ~/.config/autostart and fill it in with the following contents:<br />
<br />
[Desktop Entry]<br />
Name=your_script_name_here<br />
Exec=/path/to/your/script<br />
Type=Application<br />
Terminal=false<br />
<br />
Replace "/path/to/your/script" to the actual script being used. Set the .desktop file to be executable.<br />
Upon next login the script will be executed.<br />
<br />
==== Environment variables ====<br />
<br />
In the KDE Plasma Workspace 4.x users could set environment variables (for example, to set the SSH askpass program) prior to startup (immediately after logging) by placing them under ''~/.kde4/env''. In Plasma 5, they should be placed in ''~/.config/plasma-workspace/env''.<br />
<br />
Shutdown scripts (historically in ''~/.kde4/shutdown'') should be placed in ''~/.config/plasma-workspace/shutdown'' instead.<br />
<br />
=== Alternative applets ===<br />
<br />
In Plasma 5, applets providing the same features, for example the task manager and the icon-only task manager, can be switched on the fly without having to remove the old applet and add the new one.<br />
<br />
To do so, right click on an applet and select "Alternatives...". Afterwards, select the variant you need to use. '''Notice that all customizations to the configuration you made to the applet up to that point will be lost''' once you do this. Currently the application menu ("Kickoff") and the task manager support this feature.<br />
<br />
=== Events are no longer shown on the Plasma calendar applet ===<br />
<br />
This is a temporary regression as the PIM libraries needed for this feature are in the process of being ported to the KDE Frameworks 5. Once this port is complete, the feature will be available again.<br />
<br />
=== LibreOffice integration ===<br />
<br />
In order for LibreOffice to use native dialogs and icons, you will need to set the environment variable OOO_FORCE_DESKTOP to "kde4". Make a file called "lo-env.sh" in ~/.config/plasma-workspace/env/ with these contents:<br />
<br />
#!/bin/sh<br />
<br />
OOO_FORCE_DESKTOP="kde4"<br />
export $OOO_FORCE_DESKTOP<br />
<br />
Set it as executable, log out and back in. LibreOffice should now be integrated with the KDE workspace.<br />
<br />
=== Switching activities ===<br />
<br />
Currently the shortcut plugin, that allows switching between activities by setting shortcuts to them is disabled by default. To enable it, open System Settings ("systemsettings5"), select "Desktop Behavior", then "Activities". Navigate to the "Plugins" tab and check "global shortcuts", followed by Apply. <br />
<br />
You should be able to assign keyboard shortcuts to activities by going in the Shortcuts control panel in SYstem Settings, and selecting, under "Global shortcuts" the "Activity Manager" component. <br />
<br />
Notice that it is not possible at the moment to configure a single shortcut to cycle through activities.<br />
<br />
=== Going back to the 4.x Workspace ===<br />
<br />
<br />
<br />
<br />
=== I found a bug! What do I do ? ===<br />
<br />
==See also==<br />
<br />
[[Category:KDE]]<br />
[[zh:SDB:KDE Plasma 5]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_nodejs&diff=67875openSUSE:Packaging nodejs2014-09-22T19:44:57Z<p>MargueriteSu: /* Packages must be manually copied (Bootstraps for NPM) */</p>
<hr />
<div>{{Intro|This guide will tell you how to package nodejs packages (modules) for openSUSE.}}<br />
<br />
== NPM ==<br />
<br />
Very much like CPAN for Perl/PYPI for python, nodejs has a smiliar archive network, hosting nodejs modules, which is [https://www.npmjs.org npm]. Also npm is the pip-in-python like command in nodejs to install modules. Unlike python, most of the nodejs modules don't have any official website. This fact makes npmjs.org the best place to find latest versions and development porals for nodejs modules.<br />
<br />
== Devel repository ==<br />
<br />
All nodejs packages in openSUSE are developed at devel:languages:nodejs repository on Open Build Service.<br />
<br />
== A simple example using npm installation ==<br />
<br />
Most of the nodejs modules can be installed through npm, with some still using the legacy `configure && make && sudo make install` method, which is rather rare.<br />
<br />
The example below are taken from the nodejs-minimist package in devel:languages:nodejs repository.<br />
<br />
'''NOTE''': This method can only be used for nodejs modules that have no dependency on any other nodejs modules. Read below.<br />
<br />
<pre><br />
#<br />
# spec file for package nodejs-minimist<br />
#<br />
# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.<br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
#<br />
<br />
Name: nodejs-minimist<br />
Version: 0.2.0<br />
Release: 0<br />
License: MIT<br />
Summary: Parse argument options<br />
Url: https://github.com/substack/minimist<br />
Group: Development/Libraries/Other<br />
<br />
Source: minimist-%{version}.tar.gz<br />
BuildRequires: nodejs<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
BuildArch: noarch<br />
%{?nodejs_requires}<br />
<br />
%description<br />
This module is the guts of optimist's argument parser <br />
without all the fanciful decoration.<br />
<br />
%prep<br />
%setup -q -n minimist-%{version}<br />
<br />
%build<br />
<br />
%install<br />
%nodejs_install<br />
rm %{buildroot}%{nodejs_modulesdir}/minimist/LICENSE<br />
rm %{buildroot}%{nodejs_modulesdir}/minimist/readme.markdown<br />
<br />
%files<br />
%defattr(-,root,root)<br />
%doc LICENSE readme.markdown<br />
%{nodejs_modulesdir}/minimist<br />
<br />
%changelog<br />
</pre><br />
<br />
== Naming scheme ==<br />
<br />
nodejs packages in openSUSE are named like Python's and Perl's, starting with `<tt>nodejs-</tt>`.<br />
<br />
Note: the downloaded source tarball might be in node-mkdirp-''version''.tar.gz or minimist-''version''.tar.gz format, so it requires to use <tt>-n</tt> to explicitly specify the unpack directory in the %setup process:<br />
<br />
%setup -q -n node-mkdirp-%{version}<br />
<br />
== Most of the nodejs modules are architecture-independent ==<br />
<br />
Because they are JavaScript instead of C, so like python, "pure" nodejs package are all arch-independent, which requires this line in the specfile:<br />
<br />
BuildArch: noarch<br />
<br />
== nodejs RPM macros ==<br />
<br />
All nodejs related RPM macros are inside <tt>/etc/rpm/macros.nodejs</tt> and <tt>/etc/rpm/macros.coffeescript</tt>. Most common:<br />
<br />
=== %{?nodejs_requires} ===<br />
<br />
Use as Requires, equals to <code>Requires: nodejs</code>.<br />
<br />
=== %{nodejs_modulesdir} ===<br />
<br />
Equals to <code>/usr/lib/node_modules</code>.<br />
<br />
=== %nodejs_install ===<br />
<br />
Equals to:<br />
<br />
<pre><br />
mkdir -p %{buildroot}%{nodejs_modulesdir} \<br />
npm_config_prefix=%{buildroot}%{_prefix} npm install -g %{S:0}<br />
</pre><br />
<br />
We have to talk about npm again here. NPM can install from online URL or from local file. With a specified prefix, it will install stuff into the ./usr/lib/node_modules directory, which is %{nodejs_modulesdir}, of our Buildroot. The '-g' option means "Globally install" instead of "Locally by user", which will install into /usr/local. %{S:0} is a shortname for %{SOURCE0}, which is the content of the Source tag normally.<br />
<br />
=== %cake_build ===<br />
<br />
`cake build` in coffeescript.<br />
<br />
=== %cake_install ===<br />
<br />
`cake --prefix %{buildroot}%{nodejs_modulesdir} install` in coffeescript, will install into /usr/lib/node_modules.<br />
<br />
== NPM "dependencies" issues in package.json ==<br />
<br />
Every nodejs package that can be installed through npm must have a package.json file inside its tarball. Actually, it is a npm instruction guides npm to install the package. Here is the problem:<br />
<br />
'''If the package.json has a tag "Dependencies" with some other nodejs packages as dependency, the build process on OBS will certainly fail.'''<br />
<br />
This reason is a combination of the two below:<br />
<br />
* the build virtual machine on OBS does not have any network (so as to ensure the Island Test succeeds), unlike AUR.<br />
* npm needs to check registry.npmjs.org for dependencies anytime, no matter whether you have had the dependencies installed or not. If you once have installed nodejs modules locally, you will find the "└── minimist@0.0.8"-like symbol, this is just the symbol that proves npm does query stuff online no matter whether you have it or not (because our minimist version is 0.2.0).<br />
<br />
That is why you can install on your machine, or build a rpm on your machine, but cannot do the same thing on OBS.<br />
<br />
Here are the dirty workarounds:<br />
<br />
* Install the package on your own machine, and use `install -d <nodejs_modulesdir>; install -m 0644 <file>` method (Manual Copying) on OBS. but considering npm is a common method, such a workaround seems low...<br />
* Like this:<br />
** Unpack the tarball<br />
** copy package.json to the top directory<br />
** patch the package.json to remove the "Dependencies" tag<br />
** npm install the patched directory<br />
** install the original package.json to the BuildRoot (So end users can still have depdencies)<br />
** Use the RPM requires to track the actual dependencies<br />
<br />
An example (We may covert the procedures above to some nodejs RPM macros:<br />
<br />
<pre><br />
#<br />
# spec file for package nodejs-mkdirp<br />
#<br />
# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.<br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
#<br />
<br />
<br />
Name: nodejs-mkdirp<br />
Version: 0.5.0<br />
Release: 0<br />
License: MIT<br />
Summary: Create Directory<br />
URL: https://github.com/substack/node-mkdirp<br />
Group: Development/Libraries/Other<br />
<br />
Source: node-mkdirp-%{version}.tar.gz<br />
Patch: node-mkdirp-remove-dependency-tag.patch<br />
BuildRequires: nodejs<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}<br />
BuildArch: noarch<br />
Requires: nodejs-minimist<br />
%{?nodejs_requires}<br />
<br />
%description<br />
Create nested directorie, works like mkdir -p<br />
<br />
%prep<br />
%setup -q -n node-mkdirp-%{version}<br />
cp -r package.json ..<br />
%patch -p1<br />
pushd ..<br />
tar -czf %{SOURCE0} node-mkdirp-%{version}<br />
popd<br />
<br />
%build<br />
<br />
%install<br />
%nodejs_install<br />
rm %{buildroot}%{nodejs_modulesdir}/mkdirp/LICENSE<br />
rm %{buildroot}%{nodejs_modulesdir}/mkdirp/readme.markdown<br />
<br />
# We do not need a binary that may look similiar with unix default ones.<br />
rm -Rf %{_bindir}/mkdirp<br />
<br />
# manual install original package.json<br />
install -m 0644 ../package.json %{buildroot}%{nodejs_modulesdir}/mkdirp/<br />
<br />
%files<br />
%defattr(-,root,root)<br />
%doc LICENSE readme.markdown<br />
%{nodejs_modulesdir}/mkdirp<br />
<br />
%changelog<br />
</pre><br />
<br />
=== Failed attempts ===<br />
<br />
==== BuildRequires: xxx ====<br />
<br />
It is a python thinking, "oh, setup.py said it needs something, so we give it by RPM BuildRequires and problem solved", but npm does not buy it.<br />
<br />
==== npm link ./xxx ====<br />
<br />
If you search "npm local dependency", you will find some "solutions" on StackOverflow said you can keep the "Dependencies" tag in package.json, while using:<br />
<br />
cp -r %{nodejs_modulesdir}/minimist .<br />
npm link ./minimist<br />
<br />
to use your copy of minimist as local dependency. It will be installed into %{nodejs_modulesdir} together with your main package. Then, you can remove the dependency again to get the main package only in BuildRoot. Perfect theory!, but it will not work, because:<br />
<br />
Before the link process, npm will at first '''unlink''' the one in your %{nodejs_modulesdir} (which means, '''npm can actually find the dependency you specified through RPM Requires'''), but the "abuild" user OBS used to control the build process does not have the permissions to do that.<br />
<br />
==== npmrc or --registry ====<br />
<br />
We tried to change npm registry to a local directory by using:<br />
<br />
npm install --registry %{nodejs_modulesdir}<br />
<br />
or:<br />
<br />
npm config set regsitry %{nodejs_modulesdir}<br />
<br />
all failed because:<br />
<br />
[ 54s] npm WARN invalid config registry="/usr/lib/node_modules"<br />
[ 54s] npm WARN invalid config Must be a full url with 'http://'<br />
<br />
The same thing also applys to --proxy http://localhost because anyway it will query some URL and return something.<br />
<br />
== "Manual copy" method vs. NPM method ==<br />
<br />
== Packages must be manually copied (Bootstraps for NPM) ==<br />
<br />
These packages in d:l:nodejs must be updated with "manual copy" method, because they're build time depedencies for npm. As explained above, "manual copy" is really not a good way to package nodejs, although it's an option. But the NPM method will certainly need npm itself. So if a package, which is needed by npm to build npm, relies on npm to build itself, it will create a cycle that never ends. So we created these prerequisites plus their runtime dependencies with "manual copy" method so that we will not run into an endless loop.<br />
<br />
These packages can not be broken by introducing npm BuildRequires. See this table below (ignored the "nodejs-" prefix"<br />
<br />
{| class="wikitable sortable"<br />
|-<br />
| abbrev || ansi || ansicolors || ansistyles || archy || ansi-regex<br />
|-<br />
| block-stream || char-spinner || child-process-close || chmodr || chownr || clone<br />
|-<br />
| columnify || defaults || editor || inherits || strip-ansi || wcwidth<br />
|-<br />
| fstream || fstream-ignore || fstream-npm || github-url-from-git || github-url-from-username-repo || glob<br />
|-<br />
| graceful-fs || ini || inflight || lru-cache || minimist || mkdirp<br />
|-<br />
| once || rimraf || sigmund || wrappy || minimatch || asn1<br />
|-<br />
| assert-plus || async || aws-sign2 || bl || boom || caseless<br />
|-<br />
| cmd-shim || combined-stream || delayed-stream || core-util-is || cryptiles || ctype<br />
|-<br />
| forever-agent || form-data || hawk || hoek || http-signature || init-package-json<br />
|-<br />
| isarray || json-stringify-safe || lockfile || mime || mime-db || mime-types<br />
|-<br />
| mute-stream || node-gyp || node-uuid || nopt || normalize-package-data || npmlog<br />
|-<br />
| oauth-sign || opener || osenv || promzard || punycode || qs<br />
|-<br />
| read || read-package-json || readable-stream || request || semver || sntp<br />
|-<br />
| string_decoder || stringstream || tar || tough-cookie || tunnel-agent || which<br />
|-<br />
| async-some || config-chain || debuglog || dezalgo || fs-vacuum || npm-cache-filename<br />
|-<br />
| npm-install-checks || npm-package-arg || npm-registry-client || npm-user-validate || util-extend || npm<br />
|-<br />
| npmconf || path-is-inside || proto-list || read-installed || readdir-scoped-modules || uid-number<br />
|-<br />
| retry || sha || slide || sorted-object || text-table || -<br />
|}<br />
<br />
(to be continued).<br />
<br />
== FAQ ==<br />
<br />
=== npm ERR! network getaddrinfo enotfound ===<br />
<br />
It is because your package has some dependencies on other nodejs packages in its package.json. Nodejs does not have a configure mechanism to check dependency issues before build (RPM dependencies do not work at all for NPM, BTW. That is why you should '''check package.json''' all the time before starting to package), so it can only stop when missing dependencies in `npm install` process, w/ a different, weird and totally wrong reason.<br />
<br />
Once dependency problems are found during the npm installation process, npm will try to download the missing dependencies online, just like Python's pip. While unfortunate, even if the depdendencies are fulfilled by RPM Requires, it still needs to query registry.npmjs.org to "display" dependencies. But the build VM on openSUSE Build Service does not grant network connections, so fetching URL:<br />
<br />
[ 110s] 160 http GET https://registry.npmjs.org/minimist<br />
[ 110s] 161 info retry will retry, error on last attempt: Error: getaddrinfo ENOTFOUND<br />
<br />
will certainly fail, thus this getaddrinfo error occurs.<br />
<br />
Dependencies for any nodejs module can be found under the 'Dependencies' tag (not the 'devDependencies' tag) in the package.json file inside its tarball, or from its page on npmjs.org. Also check [[#NPM "dependencies" issues in package.json]] for solutions.<br />
<br />
=== How to debug npm issues ===<br />
<br />
You need to replace %nodejs_install macro with:<br />
<br />
npm_config_prefix=%{buildroot}%{_prefix} npm install --loglevel=silly -g %{S:0} || true<br />
echo "=========================== LOG STARTED ============================="<br />
if [ -f "npm-debug.log" ] ; then<br />
cat npm-debug.log<br />
elif<br />
echo "all fine!"<br />
done<br />
echo "=========================== LOG ENDED ==============================="<br />
<br />
And you can see anything npm did verbosely between those lines.<br />
<br />
[[Category:Packaging]]<br />
[[zh:openSUSE:Packaging_nodejs]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_nodejs&diff=67874openSUSE:Packaging nodejs2014-09-22T19:44:00Z<p>MargueriteSu: /* Packages must be manually copied (Bootstraps for NPM) */</p>
<hr />
<div>{{Intro|This guide will tell you how to package nodejs packages (modules) for openSUSE.}}<br />
<br />
== NPM ==<br />
<br />
Very much like CPAN for Perl/PYPI for python, nodejs has a smiliar archive network, hosting nodejs modules, which is [https://www.npmjs.org npm]. Also npm is the pip-in-python like command in nodejs to install modules. Unlike python, most of the nodejs modules don't have any official website. This fact makes npmjs.org the best place to find latest versions and development porals for nodejs modules.<br />
<br />
== Devel repository ==<br />
<br />
All nodejs packages in openSUSE are developed at devel:languages:nodejs repository on Open Build Service.<br />
<br />
== A simple example using npm installation ==<br />
<br />
Most of the nodejs modules can be installed through npm, with some still using the legacy `configure && make && sudo make install` method, which is rather rare.<br />
<br />
The example below are taken from the nodejs-minimist package in devel:languages:nodejs repository.<br />
<br />
'''NOTE''': This method can only be used for nodejs modules that have no dependency on any other nodejs modules. Read below.<br />
<br />
<pre><br />
#<br />
# spec file for package nodejs-minimist<br />
#<br />
# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.<br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
#<br />
<br />
Name: nodejs-minimist<br />
Version: 0.2.0<br />
Release: 0<br />
License: MIT<br />
Summary: Parse argument options<br />
Url: https://github.com/substack/minimist<br />
Group: Development/Libraries/Other<br />
<br />
Source: minimist-%{version}.tar.gz<br />
BuildRequires: nodejs<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
BuildArch: noarch<br />
%{?nodejs_requires}<br />
<br />
%description<br />
This module is the guts of optimist's argument parser <br />
without all the fanciful decoration.<br />
<br />
%prep<br />
%setup -q -n minimist-%{version}<br />
<br />
%build<br />
<br />
%install<br />
%nodejs_install<br />
rm %{buildroot}%{nodejs_modulesdir}/minimist/LICENSE<br />
rm %{buildroot}%{nodejs_modulesdir}/minimist/readme.markdown<br />
<br />
%files<br />
%defattr(-,root,root)<br />
%doc LICENSE readme.markdown<br />
%{nodejs_modulesdir}/minimist<br />
<br />
%changelog<br />
</pre><br />
<br />
== Naming scheme ==<br />
<br />
nodejs packages in openSUSE are named like Python's and Perl's, starting with `<tt>nodejs-</tt>`.<br />
<br />
Note: the downloaded source tarball might be in node-mkdirp-''version''.tar.gz or minimist-''version''.tar.gz format, so it requires to use <tt>-n</tt> to explicitly specify the unpack directory in the %setup process:<br />
<br />
%setup -q -n node-mkdirp-%{version}<br />
<br />
== Most of the nodejs modules are architecture-independent ==<br />
<br />
Because they are JavaScript instead of C, so like python, "pure" nodejs package are all arch-independent, which requires this line in the specfile:<br />
<br />
BuildArch: noarch<br />
<br />
== nodejs RPM macros ==<br />
<br />
All nodejs related RPM macros are inside <tt>/etc/rpm/macros.nodejs</tt> and <tt>/etc/rpm/macros.coffeescript</tt>. Most common:<br />
<br />
=== %{?nodejs_requires} ===<br />
<br />
Use as Requires, equals to <code>Requires: nodejs</code>.<br />
<br />
=== %{nodejs_modulesdir} ===<br />
<br />
Equals to <code>/usr/lib/node_modules</code>.<br />
<br />
=== %nodejs_install ===<br />
<br />
Equals to:<br />
<br />
<pre><br />
mkdir -p %{buildroot}%{nodejs_modulesdir} \<br />
npm_config_prefix=%{buildroot}%{_prefix} npm install -g %{S:0}<br />
</pre><br />
<br />
We have to talk about npm again here. NPM can install from online URL or from local file. With a specified prefix, it will install stuff into the ./usr/lib/node_modules directory, which is %{nodejs_modulesdir}, of our Buildroot. The '-g' option means "Globally install" instead of "Locally by user", which will install into /usr/local. %{S:0} is a shortname for %{SOURCE0}, which is the content of the Source tag normally.<br />
<br />
=== %cake_build ===<br />
<br />
`cake build` in coffeescript.<br />
<br />
=== %cake_install ===<br />
<br />
`cake --prefix %{buildroot}%{nodejs_modulesdir} install` in coffeescript, will install into /usr/lib/node_modules.<br />
<br />
== NPM "dependencies" issues in package.json ==<br />
<br />
Every nodejs package that can be installed through npm must have a package.json file inside its tarball. Actually, it is a npm instruction guides npm to install the package. Here is the problem:<br />
<br />
'''If the package.json has a tag "Dependencies" with some other nodejs packages as dependency, the build process on OBS will certainly fail.'''<br />
<br />
This reason is a combination of the two below:<br />
<br />
* the build virtual machine on OBS does not have any network (so as to ensure the Island Test succeeds), unlike AUR.<br />
* npm needs to check registry.npmjs.org for dependencies anytime, no matter whether you have had the dependencies installed or not. If you once have installed nodejs modules locally, you will find the "└── minimist@0.0.8"-like symbol, this is just the symbol that proves npm does query stuff online no matter whether you have it or not (because our minimist version is 0.2.0).<br />
<br />
That is why you can install on your machine, or build a rpm on your machine, but cannot do the same thing on OBS.<br />
<br />
Here are the dirty workarounds:<br />
<br />
* Install the package on your own machine, and use `install -d <nodejs_modulesdir>; install -m 0644 <file>` method (Manual Copying) on OBS. but considering npm is a common method, such a workaround seems low...<br />
* Like this:<br />
** Unpack the tarball<br />
** copy package.json to the top directory<br />
** patch the package.json to remove the "Dependencies" tag<br />
** npm install the patched directory<br />
** install the original package.json to the BuildRoot (So end users can still have depdencies)<br />
** Use the RPM requires to track the actual dependencies<br />
<br />
An example (We may covert the procedures above to some nodejs RPM macros:<br />
<br />
<pre><br />
#<br />
# spec file for package nodejs-mkdirp<br />
#<br />
# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.<br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
#<br />
<br />
<br />
Name: nodejs-mkdirp<br />
Version: 0.5.0<br />
Release: 0<br />
License: MIT<br />
Summary: Create Directory<br />
URL: https://github.com/substack/node-mkdirp<br />
Group: Development/Libraries/Other<br />
<br />
Source: node-mkdirp-%{version}.tar.gz<br />
Patch: node-mkdirp-remove-dependency-tag.patch<br />
BuildRequires: nodejs<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}<br />
BuildArch: noarch<br />
Requires: nodejs-minimist<br />
%{?nodejs_requires}<br />
<br />
%description<br />
Create nested directorie, works like mkdir -p<br />
<br />
%prep<br />
%setup -q -n node-mkdirp-%{version}<br />
cp -r package.json ..<br />
%patch -p1<br />
pushd ..<br />
tar -czf %{SOURCE0} node-mkdirp-%{version}<br />
popd<br />
<br />
%build<br />
<br />
%install<br />
%nodejs_install<br />
rm %{buildroot}%{nodejs_modulesdir}/mkdirp/LICENSE<br />
rm %{buildroot}%{nodejs_modulesdir}/mkdirp/readme.markdown<br />
<br />
# We do not need a binary that may look similiar with unix default ones.<br />
rm -Rf %{_bindir}/mkdirp<br />
<br />
# manual install original package.json<br />
install -m 0644 ../package.json %{buildroot}%{nodejs_modulesdir}/mkdirp/<br />
<br />
%files<br />
%defattr(-,root,root)<br />
%doc LICENSE readme.markdown<br />
%{nodejs_modulesdir}/mkdirp<br />
<br />
%changelog<br />
</pre><br />
<br />
=== Failed attempts ===<br />
<br />
==== BuildRequires: xxx ====<br />
<br />
It is a python thinking, "oh, setup.py said it needs something, so we give it by RPM BuildRequires and problem solved", but npm does not buy it.<br />
<br />
==== npm link ./xxx ====<br />
<br />
If you search "npm local dependency", you will find some "solutions" on StackOverflow said you can keep the "Dependencies" tag in package.json, while using:<br />
<br />
cp -r %{nodejs_modulesdir}/minimist .<br />
npm link ./minimist<br />
<br />
to use your copy of minimist as local dependency. It will be installed into %{nodejs_modulesdir} together with your main package. Then, you can remove the dependency again to get the main package only in BuildRoot. Perfect theory!, but it will not work, because:<br />
<br />
Before the link process, npm will at first '''unlink''' the one in your %{nodejs_modulesdir} (which means, '''npm can actually find the dependency you specified through RPM Requires'''), but the "abuild" user OBS used to control the build process does not have the permissions to do that.<br />
<br />
==== npmrc or --registry ====<br />
<br />
We tried to change npm registry to a local directory by using:<br />
<br />
npm install --registry %{nodejs_modulesdir}<br />
<br />
or:<br />
<br />
npm config set regsitry %{nodejs_modulesdir}<br />
<br />
all failed because:<br />
<br />
[ 54s] npm WARN invalid config registry="/usr/lib/node_modules"<br />
[ 54s] npm WARN invalid config Must be a full url with 'http://'<br />
<br />
The same thing also applys to --proxy http://localhost because anyway it will query some URL and return something.<br />
<br />
== "Manual copy" method vs. NPM method ==<br />
<br />
== Packages must be manually copied (Bootstraps for NPM) ==<br />
<br />
These packages in d:l:nodejs must be updated with "manual copy" method, because they're build time depedencies for npm. As explained above, "manual copy" is really not a good way to package nodejs, although it's an option. But the NPM method will certainly need npm itself. So if a package, which is needed by npm to build npm, relies on npm to build itself, it will create a cycle that never ends. So we created these prerequisites plus their runtime dependencies with "manual copy" method so that we will not run into an endless loop.<br />
<br />
These packages can not be broken by introducing npm BuildRequires. See this table below (ignored the "nodejs-" prefix"<br />
<br />
{| class="wikitable sortable"<br />
|-<br />
| abbrev || ansi || ansicolors || ansistyles || archy || ansi-regex<br />
|-<br />
| block-stream || char-spinner || child-process-close || chmodr || chownr || clone<br />
|-<br />
| columnify || defaults || editor || inherits || strip-ansi || wcwidth<br />
|-<br />
| fstream || fstream-ignore || fstream-npm || github-url-from-git || github-url-from-username-repo || glob<br />
|-<br />
| graceful-fs || ini || inflight || lru-cache || minimist || mkdirp<br />
|-<br />
| once || rimraf || sigmund || wrappy || minimatch || asn1<br />
|-<br />
| assert-plus || async || aws-sign2 || bl || boom || caseless<br />
|-<br />
| cmd-shim || combined-stream || delayed-stream || core-util-is || cryptiles || ctype<br />
|-<br />
| forever-agent || form-data || hawk || hoek || http-signature || init-package-json<br />
|-<br />
| isarray || json-stringify-safe || lockfile || mime || mime-db || mime-types<br />
|-<br />
| mute-stream || node-gyp || node-uuid || nopt || normalize-package-data || npmlog<br />
|-<br />
| oauth-sign || opener || osenv || promzard || punycode || qs<br />
|-<br />
| read || read-package-json || readable-stream || request || semver || sntp<br />
|-<br />
| string_decoder || stringstream || tar || tough-cookie || tunnel-agent || which<br />
|-<br />
| async-some || config-chain || debuglog || dezalgo || fs-vacuum || npm-cache-filename<br />
|-<br />
| npm-install-checks || npm-package-arg || npm-registry-client || npm-user-validate || - || -<br />
|-<br />
| npmconf || path-is-inside || proto-list || read-installed || readdir-scoped-modules || -<br />
|-<br />
| retry || sha || slide || sorted-object || text-table || uid-number<br />
|-<br />
| util-extend || npm || - || - || - || -<br />
|}<br />
<br />
(to be continued).<br />
<br />
== FAQ ==<br />
<br />
=== npm ERR! network getaddrinfo enotfound ===<br />
<br />
It is because your package has some dependencies on other nodejs packages in its package.json. Nodejs does not have a configure mechanism to check dependency issues before build (RPM dependencies do not work at all for NPM, BTW. That is why you should '''check package.json''' all the time before starting to package), so it can only stop when missing dependencies in `npm install` process, w/ a different, weird and totally wrong reason.<br />
<br />
Once dependency problems are found during the npm installation process, npm will try to download the missing dependencies online, just like Python's pip. While unfortunate, even if the depdendencies are fulfilled by RPM Requires, it still needs to query registry.npmjs.org to "display" dependencies. But the build VM on openSUSE Build Service does not grant network connections, so fetching URL:<br />
<br />
[ 110s] 160 http GET https://registry.npmjs.org/minimist<br />
[ 110s] 161 info retry will retry, error on last attempt: Error: getaddrinfo ENOTFOUND<br />
<br />
will certainly fail, thus this getaddrinfo error occurs.<br />
<br />
Dependencies for any nodejs module can be found under the 'Dependencies' tag (not the 'devDependencies' tag) in the package.json file inside its tarball, or from its page on npmjs.org. Also check [[#NPM "dependencies" issues in package.json]] for solutions.<br />
<br />
=== How to debug npm issues ===<br />
<br />
You need to replace %nodejs_install macro with:<br />
<br />
npm_config_prefix=%{buildroot}%{_prefix} npm install --loglevel=silly -g %{S:0} || true<br />
echo "=========================== LOG STARTED ============================="<br />
if [ -f "npm-debug.log" ] ; then<br />
cat npm-debug.log<br />
elif<br />
echo "all fine!"<br />
done<br />
echo "=========================== LOG ENDED ==============================="<br />
<br />
And you can see anything npm did verbosely between those lines.<br />
<br />
[[Category:Packaging]]<br />
[[zh:openSUSE:Packaging_nodejs]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_nodejs&diff=67873openSUSE:Packaging nodejs2014-09-22T17:51:02Z<p>MargueriteSu: /* Packages must be manually copied (Bootstraps for NPM) */</p>
<hr />
<div>{{Intro|This guide will tell you how to package nodejs packages (modules) for openSUSE.}}<br />
<br />
== NPM ==<br />
<br />
Very much like CPAN for Perl/PYPI for python, nodejs has a smiliar archive network, hosting nodejs modules, which is [https://www.npmjs.org npm]. Also npm is the pip-in-python like command in nodejs to install modules. Unlike python, most of the nodejs modules don't have any official website. This fact makes npmjs.org the best place to find latest versions and development porals for nodejs modules.<br />
<br />
== Devel repository ==<br />
<br />
All nodejs packages in openSUSE are developed at devel:languages:nodejs repository on Open Build Service.<br />
<br />
== A simple example using npm installation ==<br />
<br />
Most of the nodejs modules can be installed through npm, with some still using the legacy `configure && make && sudo make install` method, which is rather rare.<br />
<br />
The example below are taken from the nodejs-minimist package in devel:languages:nodejs repository.<br />
<br />
'''NOTE''': This method can only be used for nodejs modules that have no dependency on any other nodejs modules. Read below.<br />
<br />
<pre><br />
#<br />
# spec file for package nodejs-minimist<br />
#<br />
# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.<br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
#<br />
<br />
Name: nodejs-minimist<br />
Version: 0.2.0<br />
Release: 0<br />
License: MIT<br />
Summary: Parse argument options<br />
Url: https://github.com/substack/minimist<br />
Group: Development/Libraries/Other<br />
<br />
Source: minimist-%{version}.tar.gz<br />
BuildRequires: nodejs<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
BuildArch: noarch<br />
%{?nodejs_requires}<br />
<br />
%description<br />
This module is the guts of optimist's argument parser <br />
without all the fanciful decoration.<br />
<br />
%prep<br />
%setup -q -n minimist-%{version}<br />
<br />
%build<br />
<br />
%install<br />
%nodejs_install<br />
rm %{buildroot}%{nodejs_modulesdir}/minimist/LICENSE<br />
rm %{buildroot}%{nodejs_modulesdir}/minimist/readme.markdown<br />
<br />
%files<br />
%defattr(-,root,root)<br />
%doc LICENSE readme.markdown<br />
%{nodejs_modulesdir}/minimist<br />
<br />
%changelog<br />
</pre><br />
<br />
== Naming scheme ==<br />
<br />
nodejs packages in openSUSE are named like Python's and Perl's, starting with `<tt>nodejs-</tt>`.<br />
<br />
Note: the downloaded source tarball might be in node-mkdirp-''version''.tar.gz or minimist-''version''.tar.gz format, so it requires to use <tt>-n</tt> to explicitly specify the unpack directory in the %setup process:<br />
<br />
%setup -q -n node-mkdirp-%{version}<br />
<br />
== Most of the nodejs modules are architecture-independent ==<br />
<br />
Because they are JavaScript instead of C, so like python, "pure" nodejs package are all arch-independent, which requires this line in the specfile:<br />
<br />
BuildArch: noarch<br />
<br />
== nodejs RPM macros ==<br />
<br />
All nodejs related RPM macros are inside <tt>/etc/rpm/macros.nodejs</tt> and <tt>/etc/rpm/macros.coffeescript</tt>. Most common:<br />
<br />
=== %{?nodejs_requires} ===<br />
<br />
Use as Requires, equals to <code>Requires: nodejs</code>.<br />
<br />
=== %{nodejs_modulesdir} ===<br />
<br />
Equals to <code>/usr/lib/node_modules</code>.<br />
<br />
=== %nodejs_install ===<br />
<br />
Equals to:<br />
<br />
<pre><br />
mkdir -p %{buildroot}%{nodejs_modulesdir} \<br />
npm_config_prefix=%{buildroot}%{_prefix} npm install -g %{S:0}<br />
</pre><br />
<br />
We have to talk about npm again here. NPM can install from online URL or from local file. With a specified prefix, it will install stuff into the ./usr/lib/node_modules directory, which is %{nodejs_modulesdir}, of our Buildroot. The '-g' option means "Globally install" instead of "Locally by user", which will install into /usr/local. %{S:0} is a shortname for %{SOURCE0}, which is the content of the Source tag normally.<br />
<br />
=== %cake_build ===<br />
<br />
`cake build` in coffeescript.<br />
<br />
=== %cake_install ===<br />
<br />
`cake --prefix %{buildroot}%{nodejs_modulesdir} install` in coffeescript, will install into /usr/lib/node_modules.<br />
<br />
== NPM "dependencies" issues in package.json ==<br />
<br />
Every nodejs package that can be installed through npm must have a package.json file inside its tarball. Actually, it is a npm instruction guides npm to install the package. Here is the problem:<br />
<br />
'''If the package.json has a tag "Dependencies" with some other nodejs packages as dependency, the build process on OBS will certainly fail.'''<br />
<br />
This reason is a combination of the two below:<br />
<br />
* the build virtual machine on OBS does not have any network (so as to ensure the Island Test succeeds), unlike AUR.<br />
* npm needs to check registry.npmjs.org for dependencies anytime, no matter whether you have had the dependencies installed or not. If you once have installed nodejs modules locally, you will find the "└── minimist@0.0.8"-like symbol, this is just the symbol that proves npm does query stuff online no matter whether you have it or not (because our minimist version is 0.2.0).<br />
<br />
That is why you can install on your machine, or build a rpm on your machine, but cannot do the same thing on OBS.<br />
<br />
Here are the dirty workarounds:<br />
<br />
* Install the package on your own machine, and use `install -d <nodejs_modulesdir>; install -m 0644 <file>` method (Manual Copying) on OBS. but considering npm is a common method, such a workaround seems low...<br />
* Like this:<br />
** Unpack the tarball<br />
** copy package.json to the top directory<br />
** patch the package.json to remove the "Dependencies" tag<br />
** npm install the patched directory<br />
** install the original package.json to the BuildRoot (So end users can still have depdencies)<br />
** Use the RPM requires to track the actual dependencies<br />
<br />
An example (We may covert the procedures above to some nodejs RPM macros:<br />
<br />
<pre><br />
#<br />
# spec file for package nodejs-mkdirp<br />
#<br />
# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.<br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
#<br />
<br />
<br />
Name: nodejs-mkdirp<br />
Version: 0.5.0<br />
Release: 0<br />
License: MIT<br />
Summary: Create Directory<br />
URL: https://github.com/substack/node-mkdirp<br />
Group: Development/Libraries/Other<br />
<br />
Source: node-mkdirp-%{version}.tar.gz<br />
Patch: node-mkdirp-remove-dependency-tag.patch<br />
BuildRequires: nodejs<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}<br />
BuildArch: noarch<br />
Requires: nodejs-minimist<br />
%{?nodejs_requires}<br />
<br />
%description<br />
Create nested directorie, works like mkdir -p<br />
<br />
%prep<br />
%setup -q -n node-mkdirp-%{version}<br />
cp -r package.json ..<br />
%patch -p1<br />
pushd ..<br />
tar -czf %{SOURCE0} node-mkdirp-%{version}<br />
popd<br />
<br />
%build<br />
<br />
%install<br />
%nodejs_install<br />
rm %{buildroot}%{nodejs_modulesdir}/mkdirp/LICENSE<br />
rm %{buildroot}%{nodejs_modulesdir}/mkdirp/readme.markdown<br />
<br />
# We do not need a binary that may look similiar with unix default ones.<br />
rm -Rf %{_bindir}/mkdirp<br />
<br />
# manual install original package.json<br />
install -m 0644 ../package.json %{buildroot}%{nodejs_modulesdir}/mkdirp/<br />
<br />
%files<br />
%defattr(-,root,root)<br />
%doc LICENSE readme.markdown<br />
%{nodejs_modulesdir}/mkdirp<br />
<br />
%changelog<br />
</pre><br />
<br />
=== Failed attempts ===<br />
<br />
==== BuildRequires: xxx ====<br />
<br />
It is a python thinking, "oh, setup.py said it needs something, so we give it by RPM BuildRequires and problem solved", but npm does not buy it.<br />
<br />
==== npm link ./xxx ====<br />
<br />
If you search "npm local dependency", you will find some "solutions" on StackOverflow said you can keep the "Dependencies" tag in package.json, while using:<br />
<br />
cp -r %{nodejs_modulesdir}/minimist .<br />
npm link ./minimist<br />
<br />
to use your copy of minimist as local dependency. It will be installed into %{nodejs_modulesdir} together with your main package. Then, you can remove the dependency again to get the main package only in BuildRoot. Perfect theory!, but it will not work, because:<br />
<br />
Before the link process, npm will at first '''unlink''' the one in your %{nodejs_modulesdir} (which means, '''npm can actually find the dependency you specified through RPM Requires'''), but the "abuild" user OBS used to control the build process does not have the permissions to do that.<br />
<br />
==== npmrc or --registry ====<br />
<br />
We tried to change npm registry to a local directory by using:<br />
<br />
npm install --registry %{nodejs_modulesdir}<br />
<br />
or:<br />
<br />
npm config set regsitry %{nodejs_modulesdir}<br />
<br />
all failed because:<br />
<br />
[ 54s] npm WARN invalid config registry="/usr/lib/node_modules"<br />
[ 54s] npm WARN invalid config Must be a full url with 'http://'<br />
<br />
The same thing also applys to --proxy http://localhost because anyway it will query some URL and return something.<br />
<br />
== "Manual copy" method vs. NPM method ==<br />
<br />
== Packages must be manually copied (Bootstraps for NPM) ==<br />
<br />
These packages in d:l:nodejs must be updated with "manual copy" method, because they're build time depedencies for npm. As explained above, "manual copy" is really not a good way to package nodejs, although it's an option. But the NPM method will certainly need npm itself. So if a package, which is needed by npm to build npm, relies on npm to build itself, it will create a cycle that never ends. So we created these prerequisites plus their runtime dependencies with "manual copy" method so that we will not run into an endless loop.<br />
<br />
These packages can not be broken by introducing npm BuildRequires. See this table below (ignored the "nodejs-" prefix"<br />
<br />
{| class="wikitable sortable"<br />
|-<br />
| abbrev || ansi || ansicolors || ansistyles || archy || ansi-regex<br />
|-<br />
| block-stream || char-spinner || child-process-close || chmodr || chownr || clone<br />
|-<br />
| columnify || defaults || editor || inherits || strip-ansi || wcwidth<br />
|-<br />
| fstream || fstream-ignore || fstream-npm || github-url-from-git || github-url-from-username-repo || glob<br />
|-<br />
| graceful-fs || ini || inflight || lru-cache || minimist || mkdirp<br />
|-<br />
| once || rimraf || sigmund || wrappy || minimatch || asn1<br />
|-<br />
| assert-plus || async || aws-sign2 || bl || boom || caseless<br />
|-<br />
| cmd-shim || combined-stream || delayed-stream || core-util-is || cryptiles || ctype<br />
|-<br />
| forever-agent || form-data || hawk || hoek || http-signature || init-package-json<br />
|-<br />
| isarray || json-stringify-safe || lockfile || mime || mime-db || mime-types<br />
|-<br />
| mute-stream || node-gyp || node-uuid || nopt || normalize-package-data || npmlog<br />
|-<br />
| oauth-sign || opener || osenv || promzard || punycode || qs<br />
|-<br />
| read || read-package-json || readable-stream || request || semver || sntp<br />
|-<br />
| string_decoder || stringstream || tar || tough-cookie || tunnel-agent || which<br />
|-<br />
| 示例 || 示例 || 示例 || 示例 || 示例 || 示例<br />
|-<br />
| 示例 || 示例 || 示例 || 示例 || 示例 || 示例<br />
|}<br />
<br />
(to be continued).<br />
<br />
== FAQ ==<br />
<br />
=== npm ERR! network getaddrinfo enotfound ===<br />
<br />
It is because your package has some dependencies on other nodejs packages in its package.json. Nodejs does not have a configure mechanism to check dependency issues before build (RPM dependencies do not work at all for NPM, BTW. That is why you should '''check package.json''' all the time before starting to package), so it can only stop when missing dependencies in `npm install` process, w/ a different, weird and totally wrong reason.<br />
<br />
Once dependency problems are found during the npm installation process, npm will try to download the missing dependencies online, just like Python's pip. While unfortunate, even if the depdendencies are fulfilled by RPM Requires, it still needs to query registry.npmjs.org to "display" dependencies. But the build VM on openSUSE Build Service does not grant network connections, so fetching URL:<br />
<br />
[ 110s] 160 http GET https://registry.npmjs.org/minimist<br />
[ 110s] 161 info retry will retry, error on last attempt: Error: getaddrinfo ENOTFOUND<br />
<br />
will certainly fail, thus this getaddrinfo error occurs.<br />
<br />
Dependencies for any nodejs module can be found under the 'Dependencies' tag (not the 'devDependencies' tag) in the package.json file inside its tarball, or from its page on npmjs.org. Also check [[#NPM "dependencies" issues in package.json]] for solutions.<br />
<br />
=== How to debug npm issues ===<br />
<br />
You need to replace %nodejs_install macro with:<br />
<br />
npm_config_prefix=%{buildroot}%{_prefix} npm install --loglevel=silly -g %{S:0} || true<br />
echo "=========================== LOG STARTED ============================="<br />
if [ -f "npm-debug.log" ] ; then<br />
cat npm-debug.log<br />
elif<br />
echo "all fine!"<br />
done<br />
echo "=========================== LOG ENDED ==============================="<br />
<br />
And you can see anything npm did verbosely between those lines.<br />
<br />
[[Category:Packaging]]<br />
[[zh:openSUSE:Packaging_nodejs]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_nodejs&diff=67862openSUSE:Packaging nodejs2014-09-21T18:31:10Z<p>MargueriteSu: /* Packages must be manually copied (Bootstraps for NPM) */</p>
<hr />
<div>{{Intro|This guide will tell you how to package nodejs packages (modules) for openSUSE.}}<br />
<br />
== NPM ==<br />
<br />
Very much like CPAN for Perl/PYPI for python, nodejs has a smiliar archive network, hosting nodejs modules, which is [https://www.npmjs.org npm]. Also npm is the pip-in-python like command in nodejs to install modules. Unlike python, most of the nodejs modules don't have any official website. This fact makes npmjs.org the best place to find latest versions and development porals for nodejs modules.<br />
<br />
== Devel repository ==<br />
<br />
All nodejs packages in openSUSE are developed at devel:languages:nodejs repository on Open Build Service.<br />
<br />
== A simple example using npm installation ==<br />
<br />
Most of the nodejs modules can be installed through npm, with some still using the legacy `configure && make && sudo make install` method, which is rather rare.<br />
<br />
The example below are taken from the nodejs-minimist package in devel:languages:nodejs repository.<br />
<br />
'''NOTE''': This method can only be used for nodejs modules that have no dependency on any other nodejs modules. Read below.<br />
<br />
<pre><br />
#<br />
# spec file for package nodejs-minimist<br />
#<br />
# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.<br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
#<br />
<br />
Name: nodejs-minimist<br />
Version: 0.2.0<br />
Release: 0<br />
License: MIT<br />
Summary: Parse argument options<br />
Url: https://github.com/substack/minimist<br />
Group: Development/Libraries/Other<br />
<br />
Source: minimist-%{version}.tar.gz<br />
BuildRequires: nodejs<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
BuildArch: noarch<br />
%{?nodejs_requires}<br />
<br />
%description<br />
This module is the guts of optimist's argument parser <br />
without all the fanciful decoration.<br />
<br />
%prep<br />
%setup -q -n minimist-%{version}<br />
<br />
%build<br />
<br />
%install<br />
%nodejs_install<br />
rm %{buildroot}%{nodejs_modulesdir}/minimist/LICENSE<br />
rm %{buildroot}%{nodejs_modulesdir}/minimist/readme.markdown<br />
<br />
%files<br />
%defattr(-,root,root)<br />
%doc LICENSE readme.markdown<br />
%{nodejs_modulesdir}/minimist<br />
<br />
%changelog<br />
</pre><br />
<br />
== Naming scheme ==<br />
<br />
nodejs packages in openSUSE are named like Python's and Perl's, starting with `<tt>nodejs-</tt>`.<br />
<br />
Note: the downloaded source tarball might be in node-mkdirp-''version''.tar.gz or minimist-''version''.tar.gz format, so it requires to use <tt>-n</tt> to explicitly specify the unpack directory in the %setup process:<br />
<br />
%setup -q -n node-mkdirp-%{version}<br />
<br />
== Most of the nodejs modules are architecture-independent ==<br />
<br />
Because they are JavaScript instead of C, so like python, "pure" nodejs package are all arch-independent, which requires this line in the specfile:<br />
<br />
BuildArch: noarch<br />
<br />
== nodejs RPM macros ==<br />
<br />
All nodejs related RPM macros are inside <tt>/etc/rpm/macros.nodejs</tt> and <tt>/etc/rpm/macros.coffeescript</tt>. Most common:<br />
<br />
=== %{?nodejs_requires} ===<br />
<br />
Use as Requires, equals to <code>Requires: nodejs</code>.<br />
<br />
=== %{nodejs_modulesdir} ===<br />
<br />
Equals to <code>/usr/lib/node_modules</code>.<br />
<br />
=== %nodejs_install ===<br />
<br />
Equals to:<br />
<br />
<pre><br />
mkdir -p %{buildroot}%{nodejs_modulesdir} \<br />
npm_config_prefix=%{buildroot}%{_prefix} npm install -g %{S:0}<br />
</pre><br />
<br />
We have to talk about npm again here. NPM can install from online URL or from local file. With a specified prefix, it will install stuff into the ./usr/lib/node_modules directory, which is %{nodejs_modulesdir}, of our Buildroot. The '-g' option means "Globally install" instead of "Locally by user", which will install into /usr/local. %{S:0} is a shortname for %{SOURCE0}, which is the content of the Source tag normally.<br />
<br />
=== %cake_build ===<br />
<br />
`cake build` in coffeescript.<br />
<br />
=== %cake_install ===<br />
<br />
`cake --prefix %{buildroot}%{nodejs_modulesdir} install` in coffeescript, will install into /usr/lib/node_modules.<br />
<br />
== NPM "dependencies" issues in package.json ==<br />
<br />
Every nodejs package that can be installed through npm must have a package.json file inside its tarball. Actually, it is a npm instruction guides npm to install the package. Here is the problem:<br />
<br />
'''If the package.json has a tag "Dependencies" with some other nodejs packages as dependency, the build process on OBS will certainly fail.'''<br />
<br />
This reason is a combination of the two below:<br />
<br />
* the build virtual machine on OBS does not have any network (so as to ensure the Island Test succeeds), unlike AUR.<br />
* npm needs to check registry.npmjs.org for dependencies anytime, no matter whether you have had the dependencies installed or not. If you once have installed nodejs modules locally, you will find the "└── minimist@0.0.8"-like symbol, this is just the symbol that proves npm does query stuff online no matter whether you have it or not (because our minimist version is 0.2.0).<br />
<br />
That is why you can install on your machine, or build a rpm on your machine, but cannot do the same thing on OBS.<br />
<br />
Here are the dirty workarounds:<br />
<br />
* Install the package on your own machine, and use `install -d <nodejs_modulesdir>; install -m 0644 <file>` method (Manual Copying) on OBS. but considering npm is a common method, such a workaround seems low...<br />
* Like this:<br />
** Unpack the tarball<br />
** copy package.json to the top directory<br />
** patch the package.json to remove the "Dependencies" tag<br />
** npm install the patched directory<br />
** install the original package.json to the BuildRoot (So end users can still have depdencies)<br />
** Use the RPM requires to track the actual dependencies<br />
<br />
An example (We may covert the procedures above to some nodejs RPM macros:<br />
<br />
<pre><br />
#<br />
# spec file for package nodejs-mkdirp<br />
#<br />
# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.<br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
#<br />
<br />
<br />
Name: nodejs-mkdirp<br />
Version: 0.5.0<br />
Release: 0<br />
License: MIT<br />
Summary: Create Directory<br />
URL: https://github.com/substack/node-mkdirp<br />
Group: Development/Libraries/Other<br />
<br />
Source: node-mkdirp-%{version}.tar.gz<br />
Patch: node-mkdirp-remove-dependency-tag.patch<br />
BuildRequires: nodejs<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}<br />
BuildArch: noarch<br />
Requires: nodejs-minimist<br />
%{?nodejs_requires}<br />
<br />
%description<br />
Create nested directorie, works like mkdir -p<br />
<br />
%prep<br />
%setup -q -n node-mkdirp-%{version}<br />
cp -r package.json ..<br />
%patch -p1<br />
pushd ..<br />
tar -czf %{SOURCE0} node-mkdirp-%{version}<br />
popd<br />
<br />
%build<br />
<br />
%install<br />
%nodejs_install<br />
rm %{buildroot}%{nodejs_modulesdir}/mkdirp/LICENSE<br />
rm %{buildroot}%{nodejs_modulesdir}/mkdirp/readme.markdown<br />
<br />
# We do not need a binary that may look similiar with unix default ones.<br />
rm -Rf %{_bindir}/mkdirp<br />
<br />
# manual install original package.json<br />
install -m 0644 ../package.json %{buildroot}%{nodejs_modulesdir}/mkdirp/<br />
<br />
%files<br />
%defattr(-,root,root)<br />
%doc LICENSE readme.markdown<br />
%{nodejs_modulesdir}/mkdirp<br />
<br />
%changelog<br />
</pre><br />
<br />
=== Failed attempts ===<br />
<br />
==== BuildRequires: xxx ====<br />
<br />
It is a python thinking, "oh, setup.py said it needs something, so we give it by RPM BuildRequires and problem solved", but npm does not buy it.<br />
<br />
==== npm link ./xxx ====<br />
<br />
If you search "npm local dependency", you will find some "solutions" on StackOverflow said you can keep the "Dependencies" tag in package.json, while using:<br />
<br />
cp -r %{nodejs_modulesdir}/minimist .<br />
npm link ./minimist<br />
<br />
to use your copy of minimist as local dependency. It will be installed into %{nodejs_modulesdir} together with your main package. Then, you can remove the dependency again to get the main package only in BuildRoot. Perfect theory!, but it will not work, because:<br />
<br />
Before the link process, npm will at first '''unlink''' the one in your %{nodejs_modulesdir} (which means, '''npm can actually find the dependency you specified through RPM Requires'''), but the "abuild" user OBS used to control the build process does not have the permissions to do that.<br />
<br />
==== npmrc or --registry ====<br />
<br />
We tried to change npm registry to a local directory by using:<br />
<br />
npm install --registry %{nodejs_modulesdir}<br />
<br />
or:<br />
<br />
npm config set regsitry %{nodejs_modulesdir}<br />
<br />
all failed because:<br />
<br />
[ 54s] npm WARN invalid config registry="/usr/lib/node_modules"<br />
[ 54s] npm WARN invalid config Must be a full url with 'http://'<br />
<br />
The same thing also applys to --proxy http://localhost because anyway it will query some URL and return something.<br />
<br />
== "Manual copy" method vs. NPM method ==<br />
<br />
== Packages must be manually copied (Bootstraps for NPM) ==<br />
<br />
These packages in d:l:nodejs must be updated with "manual copy" method, because they're build time depedencies for npm. As explained above, "manual copy" is really not a good way to package nodejs, although it's an option. But the NPM method will certainly need npm itself. So if a package, which is needed by npm to build npm, relies on npm to build itself, it will create a cycle that never ends. So we created these prerequisites plus their runtime dependencies with "manual copy" method so that we will not run into an endless loop.<br />
<br />
These packages can not be broken by introducing npm BuildRequires. See this table below (ignored the "nodejs-" prefix"<br />
<br />
{| class="wikitable sortable"<br />
|-<br />
| abbrev || ansi || ansicolors || ansistyles || archy || ansi-regex<br />
|-<br />
| block-stream || char-spinner || child-process-close || chmodr || chownr || clone<br />
|-<br />
| columnify || defaults || editor || inherits || strip-ansi || wcwidth<br />
|-<br />
| fstream || fstream-ignore || fstream-npm || github-url-from-git || github-url-from-username-repo || glob<br />
|-<br />
| graceful-fs || ini || inflight || lru-cache || minimist || mkdirp<br />
|-<br />
| once || rimraf || sigmund || wrappy || minimatch || 示例<br />
|-<br />
| 示例 || 示例 || 示例 || 示例 || 示例 || 示例<br />
|-<br />
| 示例 || 示例 || 示例 || 示例 || 示例 || 示例<br />
|}<br />
<br />
(to be continued).<br />
<br />
== FAQ ==<br />
<br />
=== npm ERR! network getaddrinfo enotfound ===<br />
<br />
It is because your package has some dependencies on other nodejs packages in its package.json. Nodejs does not have a configure mechanism to check dependency issues before build (RPM dependencies do not work at all for NPM, BTW. That is why you should '''check package.json''' all the time before starting to package), so it can only stop when missing dependencies in `npm install` process, w/ a different, weird and totally wrong reason.<br />
<br />
Once dependency problems are found during the npm installation process, npm will try to download the missing dependencies online, just like Python's pip. While unfortunate, even if the depdendencies are fulfilled by RPM Requires, it still needs to query registry.npmjs.org to "display" dependencies. But the build VM on openSUSE Build Service does not grant network connections, so fetching URL:<br />
<br />
[ 110s] 160 http GET https://registry.npmjs.org/minimist<br />
[ 110s] 161 info retry will retry, error on last attempt: Error: getaddrinfo ENOTFOUND<br />
<br />
will certainly fail, thus this getaddrinfo error occurs.<br />
<br />
Dependencies for any nodejs module can be found under the 'Dependencies' tag (not the 'devDependencies' tag) in the package.json file inside its tarball, or from its page on npmjs.org. Also check [[#NPM "dependencies" issues in package.json]] for solutions.<br />
<br />
=== How to debug npm issues ===<br />
<br />
You need to replace %nodejs_install macro with:<br />
<br />
npm_config_prefix=%{buildroot}%{_prefix} npm install --loglevel=silly -g %{S:0} || true<br />
echo "=========================== LOG STARTED ============================="<br />
if [ -f "npm-debug.log" ] ; then<br />
cat npm-debug.log<br />
elif<br />
echo "all fine!"<br />
done<br />
echo "=========================== LOG ENDED ==============================="<br />
<br />
And you can see anything npm did verbosely between those lines.<br />
<br />
[[Category:Packaging]]<br />
[[zh:openSUSE:Packaging_nodejs]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_nodejs&diff=67861openSUSE:Packaging nodejs2014-09-21T06:16:23Z<p>MargueriteSu: /* npmrc or --registry */</p>
<hr />
<div>{{Intro|This guide will tell you how to package nodejs packages (modules) for openSUSE.}}<br />
<br />
== NPM ==<br />
<br />
Very much like CPAN for Perl/PYPI for python, nodejs has a smiliar archive network, hosting nodejs modules, which is [https://www.npmjs.org npm]. Also npm is the pip-in-python like command in nodejs to install modules. Unlike python, most of the nodejs modules don't have any official website. This fact makes npmjs.org the best place to find latest versions and development porals for nodejs modules.<br />
<br />
== Devel repository ==<br />
<br />
All nodejs packages in openSUSE are developed at devel:languages:nodejs repository on Open Build Service.<br />
<br />
== A simple example using npm installation ==<br />
<br />
Most of the nodejs modules can be installed through npm, with some still using the legacy `configure && make && sudo make install` method, which is rather rare.<br />
<br />
The example below are taken from the nodejs-minimist package in devel:languages:nodejs repository.<br />
<br />
'''NOTE''': This method can only be used for nodejs modules that have no dependency on any other nodejs modules. Read below.<br />
<br />
<pre><br />
#<br />
# spec file for package nodejs-minimist<br />
#<br />
# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.<br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
#<br />
<br />
Name: nodejs-minimist<br />
Version: 0.2.0<br />
Release: 0<br />
License: MIT<br />
Summary: Parse argument options<br />
Url: https://github.com/substack/minimist<br />
Group: Development/Libraries/Other<br />
<br />
Source: minimist-%{version}.tar.gz<br />
BuildRequires: nodejs<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
BuildArch: noarch<br />
%{?nodejs_requires}<br />
<br />
%description<br />
This module is the guts of optimist's argument parser <br />
without all the fanciful decoration.<br />
<br />
%prep<br />
%setup -q -n minimist-%{version}<br />
<br />
%build<br />
<br />
%install<br />
%nodejs_install<br />
rm %{buildroot}%{nodejs_modulesdir}/minimist/LICENSE<br />
rm %{buildroot}%{nodejs_modulesdir}/minimist/readme.markdown<br />
<br />
%files<br />
%defattr(-,root,root)<br />
%doc LICENSE readme.markdown<br />
%{nodejs_modulesdir}/minimist<br />
<br />
%changelog<br />
</pre><br />
<br />
== Naming scheme ==<br />
<br />
nodejs packages in openSUSE are named like Python's and Perl's, starting with `<tt>nodejs-</tt>`.<br />
<br />
Note: the downloaded source tarball might be in node-mkdirp-''version''.tar.gz or minimist-''version''.tar.gz format, so it requires to use <tt>-n</tt> to explicitly specify the unpack directory in the %setup process:<br />
<br />
%setup -q -n node-mkdirp-%{version}<br />
<br />
== Most of the nodejs modules are architecture-independent ==<br />
<br />
Because they are JavaScript instead of C, so like python, "pure" nodejs package are all arch-independent, which requires this line in the specfile:<br />
<br />
BuildArch: noarch<br />
<br />
== nodejs RPM macros ==<br />
<br />
All nodejs related RPM macros are inside <tt>/etc/rpm/macros.nodejs</tt> and <tt>/etc/rpm/macros.coffeescript</tt>. Most common:<br />
<br />
=== %{?nodejs_requires} ===<br />
<br />
Use as Requires, equals to <code>Requires: nodejs</code>.<br />
<br />
=== %{nodejs_modulesdir} ===<br />
<br />
Equals to <code>/usr/lib/node_modules</code>.<br />
<br />
=== %nodejs_install ===<br />
<br />
Equals to:<br />
<br />
<pre><br />
mkdir -p %{buildroot}%{nodejs_modulesdir} \<br />
npm_config_prefix=%{buildroot}%{_prefix} npm install -g %{S:0}<br />
</pre><br />
<br />
We have to talk about npm again here. NPM can install from online URL or from local file. With a specified prefix, it will install stuff into the ./usr/lib/node_modules directory, which is %{nodejs_modulesdir}, of our Buildroot. The '-g' option means "Globally install" instead of "Locally by user", which will install into /usr/local. %{S:0} is a shortname for %{SOURCE0}, which is the content of the Source tag normally.<br />
<br />
=== %cake_build ===<br />
<br />
`cake build` in coffeescript.<br />
<br />
=== %cake_install ===<br />
<br />
`cake --prefix %{buildroot}%{nodejs_modulesdir} install` in coffeescript, will install into /usr/lib/node_modules.<br />
<br />
== NPM "dependencies" issues in package.json ==<br />
<br />
Every nodejs package that can be installed through npm must have a package.json file inside its tarball. Actually, it is a npm instruction guides npm to install the package. Here is the problem:<br />
<br />
'''If the package.json has a tag "Dependencies" with some other nodejs packages as dependency, the build process on OBS will certainly fail.'''<br />
<br />
This reason is a combination of the two below:<br />
<br />
* the build virtual machine on OBS does not have any network (so as to ensure the Island Test succeeds), unlike AUR.<br />
* npm needs to check registry.npmjs.org for dependencies anytime, no matter whether you have had the dependencies installed or not. If you once have installed nodejs modules locally, you will find the "└── minimist@0.0.8"-like symbol, this is just the symbol that proves npm does query stuff online no matter whether you have it or not (because our minimist version is 0.2.0).<br />
<br />
That is why you can install on your machine, or build a rpm on your machine, but cannot do the same thing on OBS.<br />
<br />
Here are the dirty workarounds:<br />
<br />
* Install the package on your own machine, and use `install -d <nodejs_modulesdir>; install -m 0644 <file>` method (Manual Copying) on OBS. but considering npm is a common method, such a workaround seems low...<br />
* Like this:<br />
** Unpack the tarball<br />
** copy package.json to the top directory<br />
** patch the package.json to remove the "Dependencies" tag<br />
** npm install the patched directory<br />
** install the original package.json to the BuildRoot (So end users can still have depdencies)<br />
** Use the RPM requires to track the actual dependencies<br />
<br />
An example (We may covert the procedures above to some nodejs RPM macros:<br />
<br />
<pre><br />
#<br />
# spec file for package nodejs-mkdirp<br />
#<br />
# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.<br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
#<br />
<br />
<br />
Name: nodejs-mkdirp<br />
Version: 0.5.0<br />
Release: 0<br />
License: MIT<br />
Summary: Create Directory<br />
URL: https://github.com/substack/node-mkdirp<br />
Group: Development/Libraries/Other<br />
<br />
Source: node-mkdirp-%{version}.tar.gz<br />
Patch: node-mkdirp-remove-dependency-tag.patch<br />
BuildRequires: nodejs<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}<br />
BuildArch: noarch<br />
Requires: nodejs-minimist<br />
%{?nodejs_requires}<br />
<br />
%description<br />
Create nested directorie, works like mkdir -p<br />
<br />
%prep<br />
%setup -q -n node-mkdirp-%{version}<br />
cp -r package.json ..<br />
%patch -p1<br />
pushd ..<br />
tar -czf %{SOURCE0} node-mkdirp-%{version}<br />
popd<br />
<br />
%build<br />
<br />
%install<br />
%nodejs_install<br />
rm %{buildroot}%{nodejs_modulesdir}/mkdirp/LICENSE<br />
rm %{buildroot}%{nodejs_modulesdir}/mkdirp/readme.markdown<br />
<br />
# We do not need a binary that may look similiar with unix default ones.<br />
rm -Rf %{_bindir}/mkdirp<br />
<br />
# manual install original package.json<br />
install -m 0644 ../package.json %{buildroot}%{nodejs_modulesdir}/mkdirp/<br />
<br />
%files<br />
%defattr(-,root,root)<br />
%doc LICENSE readme.markdown<br />
%{nodejs_modulesdir}/mkdirp<br />
<br />
%changelog<br />
</pre><br />
<br />
=== Failed attempts ===<br />
<br />
==== BuildRequires: xxx ====<br />
<br />
It is a python thinking, "oh, setup.py said it needs something, so we give it by RPM BuildRequires and problem solved", but npm does not buy it.<br />
<br />
==== npm link ./xxx ====<br />
<br />
If you search "npm local dependency", you will find some "solutions" on StackOverflow said you can keep the "Dependencies" tag in package.json, while using:<br />
<br />
cp -r %{nodejs_modulesdir}/minimist .<br />
npm link ./minimist<br />
<br />
to use your copy of minimist as local dependency. It will be installed into %{nodejs_modulesdir} together with your main package. Then, you can remove the dependency again to get the main package only in BuildRoot. Perfect theory!, but it will not work, because:<br />
<br />
Before the link process, npm will at first '''unlink''' the one in your %{nodejs_modulesdir} (which means, '''npm can actually find the dependency you specified through RPM Requires'''), but the "abuild" user OBS used to control the build process does not have the permissions to do that.<br />
<br />
==== npmrc or --registry ====<br />
<br />
We tried to change npm registry to a local directory by using:<br />
<br />
npm install --registry %{nodejs_modulesdir}<br />
<br />
or:<br />
<br />
npm config set regsitry %{nodejs_modulesdir}<br />
<br />
all failed because:<br />
<br />
[ 54s] npm WARN invalid config registry="/usr/lib/node_modules"<br />
[ 54s] npm WARN invalid config Must be a full url with 'http://'<br />
<br />
The same thing also applys to --proxy http://localhost because anyway it will query some URL and return something.<br />
<br />
== "Manual copy" method vs. NPM method ==<br />
<br />
== Packages must be manually copied (Bootstraps for NPM) ==<br />
<br />
These packages in d:l:nodejs must be updated with "manual copy" method, because they're build time depedencies for npm. As explained above, "manual copy" is really not a good way to package nodejs, although it's an option. But the NPM method will certainly need npm itself. So if a package, which is needed by npm to build npm, relies on npm to build itself, it will create a cycle that never ends. So we created these prerequisites plus their runtime dependencies with "manual copy" method so that we will not run into an endless loop.<br />
<br />
These packages can not be broken by introducing npm BuildRequires. See this table below (ignored the "nodejs-" prefix"<br />
<br />
{| class="wikitable sortable"<br />
|-<br />
| abbrev || ansi || ansicolors || ansistyles || archy || ansi-regex<br />
|-<br />
| block-stream || char-spinner || child-process-close || chmodr || chownr || clone<br />
|-<br />
| columnify || defaults || editor || inherits || strip-ansi || wcwidth<br />
|-<br />
| 示例 || 示例 || 示例 || 示例 || 示例 || 示例<br />
|}<br />
<br />
(to be continued).<br />
<br />
== FAQ ==<br />
<br />
=== npm ERR! network getaddrinfo enotfound ===<br />
<br />
It is because your package has some dependencies on other nodejs packages in its package.json. Nodejs does not have a configure mechanism to check dependency issues before build (RPM dependencies do not work at all for NPM, BTW. That is why you should '''check package.json''' all the time before starting to package), so it can only stop when missing dependencies in `npm install` process, w/ a different, weird and totally wrong reason.<br />
<br />
Once dependency problems are found during the npm installation process, npm will try to download the missing dependencies online, just like Python's pip. While unfortunate, even if the depdendencies are fulfilled by RPM Requires, it still needs to query registry.npmjs.org to "display" dependencies. But the build VM on openSUSE Build Service does not grant network connections, so fetching URL:<br />
<br />
[ 110s] 160 http GET https://registry.npmjs.org/minimist<br />
[ 110s] 161 info retry will retry, error on last attempt: Error: getaddrinfo ENOTFOUND<br />
<br />
will certainly fail, thus this getaddrinfo error occurs.<br />
<br />
Dependencies for any nodejs module can be found under the 'Dependencies' tag (not the 'devDependencies' tag) in the package.json file inside its tarball, or from its page on npmjs.org. Also check [[#NPM "dependencies" issues in package.json]] for solutions.<br />
<br />
=== How to debug npm issues ===<br />
<br />
You need to replace %nodejs_install macro with:<br />
<br />
npm_config_prefix=%{buildroot}%{_prefix} npm install --loglevel=silly -g %{S:0} || true<br />
echo "=========================== LOG STARTED ============================="<br />
if [ -f "npm-debug.log" ] ; then<br />
cat npm-debug.log<br />
elif<br />
echo "all fine!"<br />
done<br />
echo "=========================== LOG ENDED ==============================="<br />
<br />
And you can see anything npm did verbosely between those lines.<br />
<br />
[[Category:Packaging]]<br />
[[zh:openSUSE:Packaging_nodejs]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67858openSUSE:Packaging Go2014-09-19T10:44:13Z<p>MargueriteSu: /* %go_requires */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Golang =<br />
<br />
Go (or Golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Golang packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Golang software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name right after the "go-" prefix. Usually vendor and source can be extracted from $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in /tmp, and install the compiled codes in ~/go/pkg/linux_${go_arch}/. (a combination of download, "go build" and "go install")<br />
<br />
So just like other new scripting languages e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find he has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from $GOROOT (where go itself installs) and $GOPATH (where go packages installs). you can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, on OBS, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
on your system, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in build log, shown as error, it'll be different because the compilers of go (such things like 6g 6l...) will: <br />
<br />
'''1st''': try to find the compiled dependencies in the about path<br />
<br />
'''2nd''': try to find source codes of the dependencies in the below path, compiles them, installs them to the $GOPATH of the user operating go, then uses them as dependencies.<br />
<br />
on OBS:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
on your system:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
'''3rd (only able in "go get" mode)''': download source codes to the $GOPATH of the user operating go and repeat the 2nd step. <br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step unless you carelessly used "go get" method to replace the default %gobuild macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
standard layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
'''contrib''' directory is used for 3rd party implementations (usually our packages). But in ~/go, go will place compiled codes in pkg and source codes in src directly (no contrib directory at all).<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRequires: xxx-devel<br />
Requires: xxx-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros, because some macros like %go_disable_brp_strip_static_archive and %go_exclusivearch are for internal use and have already be included in other macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments. So please double-check after you run "spec-cleaner -i xxx.spec", which will quote such macros.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the common shared library detection mechanism (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ===<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
== Packaging tricks for Go ==<br />
<br />
=== "tags" in go get ===<br />
<br />
Sometimes upstream e.g. gozmq told you to "go get -tags xxx $IMPORTPATH" to get a specific version , and they put files for all tags together in one repository. What's worse, newer tags like "zmq_4_x" needs files from older tags like "zmq_3_x" and "zmq_2_2" to build (Maybe that's why upstream didn't split files into different git branches). Plus the "*_test.go" files, they totally get us confused about which file can be deleted for the build of a specific version.<br />
<br />
So we can't simply deleted "zmq_3_x" files for "zmq_4_x" builds, and considering the "*_test.go" files, it'll be a total mess for us to use "%{?suse_version}" to delete files (illogic, changeable all the time). All in all, "go get -tags" is the perfect, most simple, and (maybe) only possible way.<br />
<br />
In this case, we need to manually "construct" a "go get" to replace %gobuild. As [[#Where will Golang find dependencies?]] shows, "go get" will try to find sources in $GOPATH before actually downloading online (the later will certainly break because OBS build VM doesn't have any network), it indicates that if we put sources at the right place (%goprep) and export the correct envrionment variables, "go get" is '''usuable''' on OBS. So we can change commands in specfiles like this:<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
%gobuild<br />
<br />
%install<br />
%goinstall<br />
<br />
to<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
# manual build<br />
export IMPORTPATH="github.com/alecthomas/gozmq"<br />
export BUILDFLAGS="-s -v -p 4 -x"<br />
export GOPATH=%{_builddir}/go:%{_libdir}/go/contrib<br />
%if 0%{?suse_version} >= 1230<br />
%if 0%{?suse_version} > 1315<br />
go get --tags zmq_4_x $BUILDFLAGS $IMPORTPATH<br />
%else<br />
go get --tags zmq_3_x $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
%else<br />
go get --tags zmq_2_1 $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
<br />
%install<br />
%goinstall<br />
<br />
=== $GOTOOLDIR is not rewritable ===<br />
<br />
Sometimes when building Go official packages e.g. go.tools, some binraries like "godoc" will force to install themselves into %{_libdir}/go/pkg/tool/linux_%{go_arch}, even if you have recontructed the %gobuild macro and exported GOTOOLDIR to %{_builddir}/go/pkg/tool/linux_%{go_arch}.<br />
<br />
This is intentional because Go upstream doesn't want official tools like godoc to be separately updated without the rest of go tools. But as go.tools is separately built from go main package, such decision will trigger "open /usr/lib64/go/pkg/tool/linux_amd64: Permission Denied" error on OBS.<br />
<br />
We patched go main package and provided a macro called "GOROOT_TARGET". If you:<br />
<br />
export GOROOT_TARGET="%{buildroot}%{_libdir}/go"<br />
<br />
before %gobuild, you can get this workaround.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67857openSUSE:Packaging Go2014-09-19T10:42:11Z<p>MargueriteSu: /* NOTE: Some macros can not be quoted */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Golang =<br />
<br />
Go (or Golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Golang packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Golang software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name right after the "go-" prefix. Usually vendor and source can be extracted from $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in /tmp, and install the compiled codes in ~/go/pkg/linux_${go_arch}/. (a combination of download, "go build" and "go install")<br />
<br />
So just like other new scripting languages e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find he has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from $GOROOT (where go itself installs) and $GOPATH (where go packages installs). you can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, on OBS, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
on your system, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in build log, shown as error, it'll be different because the compilers of go (such things like 6g 6l...) will: <br />
<br />
'''1st''': try to find the compiled dependencies in the about path<br />
<br />
'''2nd''': try to find source codes of the dependencies in the below path, compiles them, installs them to the $GOPATH of the user operating go, then uses them as dependencies.<br />
<br />
on OBS:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
on your system:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
'''3rd (only able in "go get" mode)''': download source codes to the $GOPATH of the user operating go and repeat the 2nd step. <br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step unless you carelessly used "go get" method to replace the default %gobuild macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
standard layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
'''contrib''' directory is used for 3rd party implementations (usually our packages). But in ~/go, go will place compiled codes in pkg and source codes in src directly (no contrib directory at all).<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRequires: xxx-devel<br />
Requires: xxx-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros, because some macros like %go_disable_brp_strip_static_archive and %go_exclusivearch are for internal use and have already be included in other macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments. So please double-check after you run "spec-cleaner -i xxx.spec", which will quote such macros.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the normal shared library finding progress (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ===<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
== Packaging tricks for Go ==<br />
<br />
=== "tags" in go get ===<br />
<br />
Sometimes upstream e.g. gozmq told you to "go get -tags xxx $IMPORTPATH" to get a specific version , and they put files for all tags together in one repository. What's worse, newer tags like "zmq_4_x" needs files from older tags like "zmq_3_x" and "zmq_2_2" to build (Maybe that's why upstream didn't split files into different git branches). Plus the "*_test.go" files, they totally get us confused about which file can be deleted for the build of a specific version.<br />
<br />
So we can't simply deleted "zmq_3_x" files for "zmq_4_x" builds, and considering the "*_test.go" files, it'll be a total mess for us to use "%{?suse_version}" to delete files (illogic, changeable all the time). All in all, "go get -tags" is the perfect, most simple, and (maybe) only possible way.<br />
<br />
In this case, we need to manually "construct" a "go get" to replace %gobuild. As [[#Where will Golang find dependencies?]] shows, "go get" will try to find sources in $GOPATH before actually downloading online (the later will certainly break because OBS build VM doesn't have any network), it indicates that if we put sources at the right place (%goprep) and export the correct envrionment variables, "go get" is '''usuable''' on OBS. So we can change commands in specfiles like this:<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
%gobuild<br />
<br />
%install<br />
%goinstall<br />
<br />
to<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
# manual build<br />
export IMPORTPATH="github.com/alecthomas/gozmq"<br />
export BUILDFLAGS="-s -v -p 4 -x"<br />
export GOPATH=%{_builddir}/go:%{_libdir}/go/contrib<br />
%if 0%{?suse_version} >= 1230<br />
%if 0%{?suse_version} > 1315<br />
go get --tags zmq_4_x $BUILDFLAGS $IMPORTPATH<br />
%else<br />
go get --tags zmq_3_x $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
%else<br />
go get --tags zmq_2_1 $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
<br />
%install<br />
%goinstall<br />
<br />
=== $GOTOOLDIR is not rewritable ===<br />
<br />
Sometimes when building Go official packages e.g. go.tools, some binraries like "godoc" will force to install themselves into %{_libdir}/go/pkg/tool/linux_%{go_arch}, even if you have recontructed the %gobuild macro and exported GOTOOLDIR to %{_builddir}/go/pkg/tool/linux_%{go_arch}.<br />
<br />
This is intentional because Go upstream doesn't want official tools like godoc to be separately updated without the rest of go tools. But as go.tools is separately built from go main package, such decision will trigger "open /usr/lib64/go/pkg/tool/linux_amd64: Permission Denied" error on OBS.<br />
<br />
We patched go main package and provided a macro called "GOROOT_TARGET". If you:<br />
<br />
export GOROOT_TARGET="%{buildroot}%{_libdir}/go"<br />
<br />
before %gobuild, you can get this workaround.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67856openSUSE:Packaging Go2014-09-19T10:35:53Z<p>MargueriteSu: /* The easy and stupid way */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Golang =<br />
<br />
Go (or Golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Golang packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Golang software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name right after the "go-" prefix. Usually vendor and source can be extracted from $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in /tmp, and install the compiled codes in ~/go/pkg/linux_${go_arch}/. (a combination of download, "go build" and "go install")<br />
<br />
So just like other new scripting languages e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find he has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from $GOROOT (where go itself installs) and $GOPATH (where go packages installs). you can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, on OBS, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
on your system, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in build log, shown as error, it'll be different because the compilers of go (such things like 6g 6l...) will: <br />
<br />
'''1st''': try to find the compiled dependencies in the about path<br />
<br />
'''2nd''': try to find source codes of the dependencies in the below path, compiles them, installs them to the $GOPATH of the user operating go, then uses them as dependencies.<br />
<br />
on OBS:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
on your system:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
'''3rd (only able in "go get" mode)''': download source codes to the $GOPATH of the user operating go and repeat the 2nd step. <br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step unless you carelessly used "go get" method to replace the default %gobuild macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
standard layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
'''contrib''' directory is used for 3rd party implementations (usually our packages). But in ~/go, go will place compiled codes in pkg and source codes in src directly (no contrib directory at all).<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRequires: xxx-devel<br />
Requires: xxx-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros, because some macros like %go_disable_brp_strip_static_archive and %go_exclusivearch are for internal use and have already be included in other macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the normal shared library finding progress (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ===<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
== Packaging tricks for Go ==<br />
<br />
=== "tags" in go get ===<br />
<br />
Sometimes upstream e.g. gozmq told you to "go get -tags xxx $IMPORTPATH" to get a specific version , and they put files for all tags together in one repository. What's worse, newer tags like "zmq_4_x" needs files from older tags like "zmq_3_x" and "zmq_2_2" to build (Maybe that's why upstream didn't split files into different git branches). Plus the "*_test.go" files, they totally get us confused about which file can be deleted for the build of a specific version.<br />
<br />
So we can't simply deleted "zmq_3_x" files for "zmq_4_x" builds, and considering the "*_test.go" files, it'll be a total mess for us to use "%{?suse_version}" to delete files (illogic, changeable all the time). All in all, "go get -tags" is the perfect, most simple, and (maybe) only possible way.<br />
<br />
In this case, we need to manually "construct" a "go get" to replace %gobuild. As [[#Where will Golang find dependencies?]] shows, "go get" will try to find sources in $GOPATH before actually downloading online (the later will certainly break because OBS build VM doesn't have any network), it indicates that if we put sources at the right place (%goprep) and export the correct envrionment variables, "go get" is '''usuable''' on OBS. So we can change commands in specfiles like this:<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
%gobuild<br />
<br />
%install<br />
%goinstall<br />
<br />
to<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
# manual build<br />
export IMPORTPATH="github.com/alecthomas/gozmq"<br />
export BUILDFLAGS="-s -v -p 4 -x"<br />
export GOPATH=%{_builddir}/go:%{_libdir}/go/contrib<br />
%if 0%{?suse_version} >= 1230<br />
%if 0%{?suse_version} > 1315<br />
go get --tags zmq_4_x $BUILDFLAGS $IMPORTPATH<br />
%else<br />
go get --tags zmq_3_x $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
%else<br />
go get --tags zmq_2_1 $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
<br />
%install<br />
%goinstall<br />
<br />
=== $GOTOOLDIR is not rewritable ===<br />
<br />
Sometimes when building Go official packages e.g. go.tools, some binraries like "godoc" will force to install themselves into %{_libdir}/go/pkg/tool/linux_%{go_arch}, even if you have recontructed the %gobuild macro and exported GOTOOLDIR to %{_builddir}/go/pkg/tool/linux_%{go_arch}.<br />
<br />
This is intentional because Go upstream doesn't want official tools like godoc to be separately updated without the rest of go tools. But as go.tools is separately built from go main package, such decision will trigger "open /usr/lib64/go/pkg/tool/linux_amd64: Permission Denied" error on OBS.<br />
<br />
We patched go main package and provided a macro called "GOROOT_TARGET". If you:<br />
<br />
export GOROOT_TARGET="%{buildroot}%{_libdir}/go"<br />
<br />
before %gobuild, you can get this workaround.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67855openSUSE:Packaging Go2014-09-19T10:23:38Z<p>MargueriteSu: /* Add new */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Golang =<br />
<br />
Go (or Golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Golang packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Golang software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name right after the "go-" prefix. Usually vendor and source can be extracted from $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in /tmp, and install the compiled codes in ~/go/pkg/linux_${go_arch}/. (a combination of download, "go build" and "go install")<br />
<br />
So just like other new scripting languages e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find he has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from $GOROOT (where go itself installs) and $GOPATH (where go packages installs). you can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, on OBS, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
on your system, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in build log, shown as error, it'll be different because the compilers of go (such things like 6g 6l...) will: <br />
<br />
'''1st''': try to find the compiled dependencies in the about path<br />
<br />
'''2nd''': try to find source codes of the dependencies in the below path, compiles them, installs them to the $GOPATH of the user operating go, then uses them as dependencies.<br />
<br />
on OBS:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
on your system:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
'''3rd (only able in "go get" mode)''': download source codes to the $GOPATH of the user operating go and repeat the 2nd step. <br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step unless you carelessly used "go get" method to replace the default %gobuild macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
standard layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
'''contrib''' directory is used for 3rd party implementations (usually our packages). But in ~/go, go will place compiled codes in pkg and source codes in src directly (no contrib directory at all).<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source0: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%{go_disable_brp_strip_static_archive}<br />
<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros, because some macros like %go_disable_brp_strip_static_archive and %go_exclusivearch are for internal use and have already be included in other macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the normal shared library finding progress (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ===<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
== Packaging tricks for Go ==<br />
<br />
=== "tags" in go get ===<br />
<br />
Sometimes upstream e.g. gozmq told you to "go get -tags xxx $IMPORTPATH" to get a specific version , and they put files for all tags together in one repository. What's worse, newer tags like "zmq_4_x" needs files from older tags like "zmq_3_x" and "zmq_2_2" to build (Maybe that's why upstream didn't split files into different git branches). Plus the "*_test.go" files, they totally get us confused about which file can be deleted for the build of a specific version.<br />
<br />
So we can't simply deleted "zmq_3_x" files for "zmq_4_x" builds, and considering the "*_test.go" files, it'll be a total mess for us to use "%{?suse_version}" to delete files (illogic, changeable all the time). All in all, "go get -tags" is the perfect, most simple, and (maybe) only possible way.<br />
<br />
In this case, we need to manually "construct" a "go get" to replace %gobuild. As [[#Where will Golang find dependencies?]] shows, "go get" will try to find sources in $GOPATH before actually downloading online (the later will certainly break because OBS build VM doesn't have any network), it indicates that if we put sources at the right place (%goprep) and export the correct envrionment variables, "go get" is '''usuable''' on OBS. So we can change commands in specfiles like this:<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
%gobuild<br />
<br />
%install<br />
%goinstall<br />
<br />
to<br />
<br />
%build<br />
%goprep github.com/alecthomas/gozmq<br />
# manual build<br />
export IMPORTPATH="github.com/alecthomas/gozmq"<br />
export BUILDFLAGS="-s -v -p 4 -x"<br />
export GOPATH=%{_builddir}/go:%{_libdir}/go/contrib<br />
%if 0%{?suse_version} >= 1230<br />
%if 0%{?suse_version} > 1315<br />
go get --tags zmq_4_x $BUILDFLAGS $IMPORTPATH<br />
%else<br />
go get --tags zmq_3_x $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
%else<br />
go get --tags zmq_2_1 $BUILDFLAGS $IMPORTPATH<br />
%endif<br />
<br />
%install<br />
%goinstall<br />
<br />
=== $GOTOOLDIR is not rewritable ===<br />
<br />
Sometimes when building Go official packages e.g. go.tools, some binraries like "godoc" will force to install themselves into %{_libdir}/go/pkg/tool/linux_%{go_arch}, even if you have recontructed the %gobuild macro and exported GOTOOLDIR to %{_builddir}/go/pkg/tool/linux_%{go_arch}.<br />
<br />
This is intentional because Go upstream doesn't want official tools like godoc to be separately updated without the rest of go tools. But as go.tools is separately built from go main package, such decision will trigger "open /usr/lib64/go/pkg/tool/linux_amd64: Permission Denied" error on OBS.<br />
<br />
We patched go main package and provided a macro called "GOROOT_TARGET". If you:<br />
<br />
export GOROOT_TARGET="%{buildroot}%{_libdir}/go"<br />
<br />
before %gobuild, you can get this workaround.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67853openSUSE:Packaging Go2014-09-19T10:05:18Z<p>MargueriteSu: /* Macros */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Golang =<br />
<br />
Go (or Golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Golang packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Golang software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name right after the "go-" prefix. Usually vendor and source can be extracted from $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in /tmp, and install the compiled codes in ~/go/pkg/linux_${go_arch}/. (a combination of download, "go build" and "go install")<br />
<br />
So just like other new scripting languages e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find he has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from $GOROOT (where go itself installs) and $GOPATH (where go packages installs). you can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, on OBS, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
on your system, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in build log, shown as error, it'll be different because the compilers of go (such things like 6g 6l...) will: <br />
<br />
'''1st''': try to find the compiled dependencies in the about path<br />
<br />
'''2nd''': try to find source codes of the dependencies in the below path, compiles them, installs them to the $GOPATH of the user operating go, then uses them as dependencies.<br />
<br />
on OBS:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
on your system:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
'''3rd (only able in "go get" mode)''': download source codes to the $GOPATH of the user operating go and repeat the 2nd step. <br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step unless you carelessly used "go get" method to replace the default %gobuild macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
standard layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
'''contrib''' directory is used for 3rd party implementations (usually our packages). But in ~/go, go will place compiled codes in pkg and source codes in src directly (no contrib directory at all).<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source0: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%{go_disable_brp_strip_static_archive}<br />
<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros, because some macros like %go_disable_brp_strip_static_archive and %go_exclusivearch are for internal use and have already be included in other macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the normal shared library finding progress (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ===<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67852openSUSE:Packaging Go2014-09-19T10:02:50Z<p>MargueriteSu: /* Where will Golang find dependencies? */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Golang =<br />
<br />
Go (or Golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Golang packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Golang software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name right after the "go-" prefix. Usually vendor and source can be extracted from $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in /tmp, and install the compiled codes in ~/go/pkg/linux_${go_arch}/. (a combination of download, "go build" and "go install")<br />
<br />
So just like other new scripting languages e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find he has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from $GOROOT (where go itself installs) and $GOPATH (where go packages installs). you can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, on OBS, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
on your system, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in build log, shown as error, it'll be different because the compilers of go (such things like 6g 6l...) will: <br />
<br />
'''1st''': try to find the compiled dependencies in the about path<br />
<br />
'''2nd''': try to find source codes of the dependencies in the below path, compiles them, installs them to the $GOPATH of the user operating go, then uses them as dependencies.<br />
<br />
on OBS:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
on your system:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
'''3rd (only able in "go get" mode)''': download source codes to the $GOPATH of the user operating go and repeat the 2nd step. <br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step unless you carelessly used "go get" method to replace the default %gobuild macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
standard layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
'''contrib''' directory is used for 3rd party implementations (usually our packages). But in ~/go, go will place compiled codes in pkg and source codes in src directly (no contrib directory at all).<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source0: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%{go_disable_brp_strip_static_archive}<br />
<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the normal shared library finding progress (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ===<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67851openSUSE:Packaging Go2014-09-19T10:01:53Z<p>MargueriteSu: /* Where will Golang find dependencies? */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Golang =<br />
<br />
Go (or Golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Golang packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Golang software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name right after the "go-" prefix. Usually vendor and source can be extracted from $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in /tmp, and install the compiled codes in ~/go/pkg/linux_${go_arch}/. (a combination of download, "go build" and "go install")<br />
<br />
So just like other new scripting languages e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find he has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from $GOROOT (where go itself installs) and $GOPATH (where go packages installs). you can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, on OBS, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
on your system, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in build log, shown as error, it'll be different because the compilers of go (such things like 6g 6l...) will: <br />
<br />
'''1st''': try to find the compiled dependencies in the about path<br />
'''2nd''': try to find source codes of the dependencies in the below path, compiles them, installs them to the $GOPATH of the user operating go, then uses them as dependencies.<br />
<br />
on OBS:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
on your system:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
'''3rd (only able in "go get" mode)''': download source codes to the $GOPATH of the user operating go and repeat the 2nd step. <br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step unless you carelessly used "go get" method to replace the default %gobuild macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
standard layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
'''contrib''' directory is used for 3rd party implementations (usually our packages). But in ~/go, go will place compiled codes in pkg and source codes in src directly (no contrib directory at all).<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source0: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%{go_disable_brp_strip_static_archive}<br />
<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the normal shared library finding progress (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ===<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67850openSUSE:Packaging Go2014-09-19T09:28:15Z<p>MargueriteSu: /* undefined reference to SOME_C_FUNCTION = */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Golang =<br />
<br />
Go (or Golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Golang packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Golang software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name right after the "go-" prefix. Usually vendor and source can be extracted from $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in /tmp, and install the compiled codes in ~/go/pkg/linux_${go_arch}/. (a combination of download, "go build" and "go install")<br />
<br />
So just like other new scripting languages e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find he has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from $GOROOT (where go itself installs) and $GOPATH (where go packages installs). you can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, on OBS, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
on your system, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in build log, shown as error, it'll be different because the compiler of go (such things look like 5g 6c...) will: <br />
<br />
1st: try to find the compiled dependencies in the about path<br />
2nd: try to find source codes of the dependencies in the below path, compiles them, installs them to the $GOPATH of the user operating go, then uses them as dependencies.<br />
<br />
on OBS:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
on your system:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
3rd (only able in "go get" mode): download source codes to the $GOPATH of the user operating go and repeat the 2nd step. <br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step unless you carelessly used "go get" method to replace the default %gobuild macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
standard layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
'''contrib''' directory is used for 3rd party implementations (usually our packages). But in ~/go, go will place compiled codes in pkg and source codes in src directly (no contrib directory at all).<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source0: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%{go_disable_brp_strip_static_archive}<br />
<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the normal shared library finding progress (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ===<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67849openSUSE:Packaging Go2014-09-19T09:27:39Z<p>MargueriteSu: /* object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Golang =<br />
<br />
Go (or Golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Golang packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Golang software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name right after the "go-" prefix. Usually vendor and source can be extracted from $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in /tmp, and install the compiled codes in ~/go/pkg/linux_${go_arch}/. (a combination of download, "go build" and "go install")<br />
<br />
So just like other new scripting languages e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find he has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from $GOROOT (where go itself installs) and $GOPATH (where go packages installs). you can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, on OBS, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
on your system, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in build log, shown as error, it'll be different because the compiler of go (such things look like 5g 6c...) will: <br />
<br />
1st: try to find the compiled dependencies in the about path<br />
2nd: try to find source codes of the dependencies in the below path, compiles them, installs them to the $GOPATH of the user operating go, then uses them as dependencies.<br />
<br />
on OBS:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
on your system:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
3rd (only able in "go get" mode): download source codes to the $GOPATH of the user operating go and repeat the 2nd step. <br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step unless you carelessly used "go get" method to replace the default %gobuild macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
standard layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
'''contrib''' directory is used for 3rd party implementations (usually our packages). But in ~/go, go will place compiled codes in pkg and source codes in src directly (no contrib directory at all).<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source0: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%{go_disable_brp_strip_static_archive}<br />
<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the normal shared library finding progress (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ====<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
=== stat "bitbucket.org/taruti/ssh.go" No such file or directory ===<br />
<br />
It's because "*.go" is no longer allowable for import path in new versions of Go.<br />
<br />
So in this case, you need to change<br />
<br />
%goprep bitbucket.org/taruti/ssh.go<br />
<br />
to<br />
<br />
%goprep bitbucket.org/taruti/ssh-go<br />
<br />
and '''mention that in .changes file''' so developers using our repository will know the change.<br />
<br />
But '''usually it indicates this project is too old and you should find newer implementations if upstream didn't adapt to the change themselves.''' In the above case, you should use "code.google.com/p/go.crypto/ssh" which is newer and official.<br />
<br />
=== Add new ===<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67829openSUSE:Packaging Go2014-09-17T10:23:07Z<p>MargueriteSu: </p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Golang software packages for openSUSE using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Golang =<br />
<br />
Go (or Golang, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Golang packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Golang software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name right after the "go-" prefix. Usually vendor and source can be extracted from $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click "branch" button for any existing package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build for this repository.<br />
<br />
= Things you should know before packaging =<br />
<br />
== Golang do have dependencies ==<br />
<br />
Golang provides a method called "go get", which is commonly used by upstream. It will fetch the source code of the package plus source codes for all the dependencies, build them in /tmp, and install the compiled codes in ~/go/pkg/linux_${go_arch}/. (a combination of download, "go build" and "go install")<br />
<br />
So just like other new scripting languages e.g. Nodejs, it will confuse new packagers with dependencies. Some may think this package has no other dependencies except the "go" main package, run into this mess, and find he has about 30+ dependencies to package first. '''Please check your ~/go directory first''' before asserting that this package has no other dependencies and running into chaos.<br />
<br />
== Where will Golang find dependencies? ==<br />
<br />
Golang will find dependencies from $GOROOT (where go itself installs) and $GOPATH (where go packages installs). you can run:<br />
<br />
go env<br />
<br />
to find out yours. Basically, on OBS, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
on your system, it'll be:<br />
<br />
/usr/lib(64)/go/pkg/linux_%{go_arch}/ ($GOROOT)<br />
/usr/lib(64)/go/contrib/pkg/linux_%{go_arch}/ ($GOPATH)<br />
~/go/pkg/linux_%{go_arch}/ ($GOPATH)<br />
<br />
But in build log, shown as error, it'll be different because the compiler of go (such things look like 5g 6c...) will: <br />
<br />
1st: try to find the compiled dependencies in the about path<br />
2nd: try to find source codes of the dependencies in the below path, compiles them, installs them to the $GOPATH of the user operating go, then uses them as dependencies.<br />
<br />
on OBS:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
/home/abuild/rpmbuild/BUILD/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
on your system:<br />
<br />
/usr/lib64/go/src/pkg/$IMPORTPATH ($GOROOT)<br />
~/go/src/$IMPORTPATH ($GOPATH)<br />
/usr/lib64/go/contrib/src/$IMPORTPATH ($GOPATH)<br />
<br />
3rd (only able in "go get" mode): download source codes to the $GOPATH of the user operating go and repeat the 2nd step. <br />
<br />
So if OBS gives you an error, it usually happens at the 2nd step unless you carelessly used "go get" method to replace the default %gobuild macro, which will show such errors like "can't find git" or "network not reachable".<br />
<br />
== The Go layout ==<br />
<br />
standard layout for go looks like this:<br />
<br />
go<br />
.. pkg<br />
.. linux_%{go_arch}<br />
.. $IMPORTPATHs for packages (compiled codes reside here)<br />
.. src<br />
.. pkg<br />
.. $IMPORTPATHs for packages (source codes reside here)<br />
.. contrib<br />
.. pkg (same as above)<br />
.. src (same as above)<br />
<br />
'''contrib''' directory is used for 3rd party implementations (usually our packages). But in ~/go, go will place compiled codes in pkg and source codes in src directly (no contrib directory at all).<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source0: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%{go_disable_brp_strip_static_archive}<br />
<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the normal shared library finding progress (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
...<br />
[ follwing with a very looong "goroutine" ]<br />
...<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the panic. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ====<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67827openSUSE:Packaging Go2014-09-16T18:24:35Z<p>MargueriteSu: </p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Go software packages for openSUSE and others using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Go =<br />
<br />
Go (Golang in Debian, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Go packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Go software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name. Usually vendor and source can be extracted from its $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click branch button for any package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build inside this repository.<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source0: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%{go_disable_brp_strip_static_archive}<br />
<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the normal shared library finding progress (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Dependencies (Requires) ==<br />
<br />
Golang packages are "static" builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
=== Easy cheat sheet ===<br />
<br />
Remember this: '''Your BuildRequires is your Requires'''.<br />
<br />
It may sound weird, but to some extent Golang is like Python. You can run Python codes in binary-compiled code (*.pyc) or source code (*.py), and you can run Golang codes in binary-compiled code (*.a) or source code (*.go) too. (But unlike Python, "go run" can't run compiled codes.)<br />
<br />
So what you need in your build environment will be what you will need for you runtime environment.<br />
<br />
Don't be fooled by the ".a" suffix. In C this means static, you don't need to install shared lib dependencies for it then. But in Golang, it will not absorb all the dependencies. It will not absorb the C dependency codes like those from GTK either.<br />
<br />
=== Learn the hard way ===<br />
<br />
==== "Pure" Golang packages ====<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
goroutine 16 [running]:<br />
runtime.panic(0x64c540, 0xc208045cc0)<br />
/usr/lib64/go/src/pkg/runtime/panic.c:279 +0xf5<br />
code.google.com/p/log4go.Crash(0xc208000450, 0x1, 0x1)<br />
/home/abuild/rpmbuild/BUILD/go/src/code.google.com/p/log4go/wrapper.go:39 +0x117<br />
main.func·015()<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/frontend/termbox/main.go:668 +0x9f<br />
runtime.panic(0x6f4a80, 0xb09f13)<br />
/usr/lib64/go/src/pkg/runtime/panic.c:248 +0x18d<br />
main.setSchemeSettings()<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/frontend/termbox/main.go:617 +0x56a<br />
main.(*tbfe).loop(0xc2080febd0)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/frontend/termbox/main.go:397 +0x1bc<br />
main.main()<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/frontend/termbox/main.go:676 +0x1df<br />
<br />
goroutine 19 [finalizer wait]:<br />
runtime.park(0x42b6d0, 0xb1d4e8, 0xb0cda9)<br />
/usr/lib64/go/src/pkg/runtime/proc.c:1369 +0x89<br />
runtime.parkunlock(0xb1d4e8, 0xb0cda9)<br />
/usr/lib64/go/src/pkg/runtime/proc.c:1385 +0x3b<br />
runfinq()<br />
/usr/lib64/go/src/pkg/runtime/mgc0.c:2644 +0xcf<br />
runtime.goexit()<br />
/usr/lib64/go/src/pkg/runtime/proc.c:1445<br />
<br />
goroutine 21 [syscall]:<br />
os/signal.loop()<br />
/usr/lib64/go/src/pkg/os/signal/signal_unix.go:21 +0x1e<br />
created by os/signal.init·1<br />
/usr/lib64/go/src/pkg/os/signal/signal_unix.go:27 +0x32<br />
<br />
goroutine 22 [chan receive]:<br />
github.com/quarnster/util/text.(*SerializedBuffer).worker(0xc20805a248)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/quarnster/util/text/serialized_buffer.go:40 +0x5e<br />
created by github.com/quarnster/util/text.(*SerializedBuffer).init<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/quarnster/util/text/serialized_buffer.go:26 +0x88<br />
<br />
goroutine 23 [syscall]:<br />
syscall.Syscall(0x0, 0x3, 0xc2080c5e98, 0x10000, 0x0, 0x0, 0x0)<br />
/usr/lib64/go/src/pkg/syscall/asm_linux_amd64.s:21 +0x5<br />
syscall.read(0x3, 0xc2080c5e98, 0x10000, 0x10000, 0x0, 0x0, 0x0)<br />
/usr/lib64/go/src/pkg/syscall/zsyscall_linux_amd64.go:838 +0x75<br />
syscall.Read(0x3, 0xc2080c5e98, 0x10000, 0x10000, 0x0, 0x0, 0x0)<br />
/usr/lib64/go/src/pkg/syscall/syscall_unix.go:136 +0x5c<br />
github.com/howeyc/fsnotify.(*Watcher).readEvents(0xc2080044e0)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/howeyc/fsnotify/fsnotify_linux.go:219 +0x133<br />
created by github.com/howeyc/fsnotify.NewWatcher<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/howeyc/fsnotify/fsnotify_linux.go:126 +0x288<br />
<br />
goroutine 24 [chan receive]:<br />
github.com/howeyc/fsnotify.(*Watcher).purgeEvents(0xc2080044e0)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/howeyc/fsnotify/fsnotify.go:21 +0x51<br />
created by github.com/howeyc/fsnotify.NewWatcher<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/howeyc/fsnotify/fsnotify_linux.go:127 +0x2a0<br />
<br />
goroutine 25 [chan receive]:<br />
github.com/limetext/lime/backend.(*myLogWriter).handle(0xc208042090)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/editor.go:110 +0x70<br />
created by github.com/limetext/lime/backend.newMyLogWriter<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/editor.go:105 +0x69<br />
<br />
goroutine 26 [chan receive]:<br />
github.com/limetext/lime/backend.(*Editor).inputthread(0xc20807c000)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/editor.go:360 +0xb2<br />
created by github.com/limetext/lime/backend.GetEditor<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/editor.go:160 +0x42d<br />
<br />
goroutine 27 [select]:<br />
github.com/limetext/lime/backend.(*Editor).observeFiles(0xc20807c000)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/editor.go:432 +0x289<br />
created by github.com/limetext/lime/backend.GetEditor<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/editor.go:161 +0x448<br />
<br />
goroutine 17 [syscall]:<br />
runtime.goexit()<br />
/usr/lib64/go/src/pkg/runtime/proc.c:1445<br />
<br />
goroutine 28 [select]:<br />
code.google.com/p/log4go.func·002()<br />
/home/abuild/rpmbuild/BUILD/go/src/code.google.com/p/log4go/filelog.go:84 +0x8ac<br />
created by code.google.com/p/log4go.NewFileLogWriter<br />
/home/abuild/rpmbuild/BUILD/go/src/code.google.com/p/log4go/filelog.go:116 +0x2c4<br />
<br />
goroutine 30 [chan receive]:<br />
main.(*tbfe).renderthread(0xc2080febd0)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/frontend/termbox/main.go:369 +0x90<br />
created by main.main<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/frontend/termbox/main.go:675 +0x1cf<br />
<br />
goroutine 31 [chan receive]:<br />
github.com/limetext/lime/backend.(*View).parsethread(0xc208106900)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/view.go:236 +0x151<br />
created by github.com/limetext/lime/backend.newView<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/view.go:84 +0x139<br />
<br />
goroutine 33 [chan receive]:<br />
github.com/quarnster/util/text.(*SerializedBuffer).worker(0xc20805a718)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/quarnster/util/text/serialized_buffer.go:40 +0x5e<br />
created by github.com/quarnster/util/text.(*SerializedBuffer).init<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/quarnster/util/text/serialized_buffer.go:26 +0x88<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the "panic: runtime error: invalid memory address or nil pointer dereference" problem. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
==== Golang wrapper packages for C/C++ ====<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ====<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67826openSUSE:Packaging Go2014-09-16T18:07:21Z<p>MargueriteSu: /* "Pure" Golang packages */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Go software packages for openSUSE and others using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Go =<br />
<br />
Go (Golang in Debian, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Go packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Go software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name. Usually vendor and source can be extracted from its $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click branch button for any package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build inside this repository.<br />
<br />
= Dependencies (Requires) =<br />
<br />
Golang packages are static builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
== "Pure" Golang packages ==<br />
<br />
If you skip the essential Requires (usually are those '''essential''' to build the package, eg. go-log4go for lime), end user will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library, which will be:<br />
<br />
<pre><br />
test.go:2:8: cannot find package "code.google.com/p/log4go" in any of:<br />
/usr/lib64/go/src/pkg/code.google.com/p/log4go (from $GOROOT)<br />
/home/marguerite/go/src/code.google.com/p/log4go (from $GOPATH)<br />
/usr/lib64/go/contrib/src/code.google.com/p/log4go<br />
</pre><br />
<br />
But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then:<br />
<br />
<pre><br />
panic: runtime error: invalid memory address or nil pointer dereference [recovered]<br />
panic: ([]interface {}) (0x64c540,0xc208045cc0)<br />
[signal 0xb code=0x1 addr=0x0 pc=0x4165ba]<br />
<br />
goroutine 16 [running]:<br />
runtime.panic(0x64c540, 0xc208045cc0)<br />
/usr/lib64/go/src/pkg/runtime/panic.c:279 +0xf5<br />
code.google.com/p/log4go.Crash(0xc208000450, 0x1, 0x1)<br />
/home/abuild/rpmbuild/BUILD/go/src/code.google.com/p/log4go/wrapper.go:39 +0x117<br />
main.func·015()<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/frontend/termbox/main.go:668 +0x9f<br />
runtime.panic(0x6f4a80, 0xb09f13)<br />
/usr/lib64/go/src/pkg/runtime/panic.c:248 +0x18d<br />
main.setSchemeSettings()<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/frontend/termbox/main.go:617 +0x56a<br />
main.(*tbfe).loop(0xc2080febd0)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/frontend/termbox/main.go:397 +0x1bc<br />
main.main()<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/frontend/termbox/main.go:676 +0x1df<br />
<br />
goroutine 19 [finalizer wait]:<br />
runtime.park(0x42b6d0, 0xb1d4e8, 0xb0cda9)<br />
/usr/lib64/go/src/pkg/runtime/proc.c:1369 +0x89<br />
runtime.parkunlock(0xb1d4e8, 0xb0cda9)<br />
/usr/lib64/go/src/pkg/runtime/proc.c:1385 +0x3b<br />
runfinq()<br />
/usr/lib64/go/src/pkg/runtime/mgc0.c:2644 +0xcf<br />
runtime.goexit()<br />
/usr/lib64/go/src/pkg/runtime/proc.c:1445<br />
<br />
goroutine 21 [syscall]:<br />
os/signal.loop()<br />
/usr/lib64/go/src/pkg/os/signal/signal_unix.go:21 +0x1e<br />
created by os/signal.init·1<br />
/usr/lib64/go/src/pkg/os/signal/signal_unix.go:27 +0x32<br />
<br />
goroutine 22 [chan receive]:<br />
github.com/quarnster/util/text.(*SerializedBuffer).worker(0xc20805a248)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/quarnster/util/text/serialized_buffer.go:40 +0x5e<br />
created by github.com/quarnster/util/text.(*SerializedBuffer).init<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/quarnster/util/text/serialized_buffer.go:26 +0x88<br />
<br />
goroutine 23 [syscall]:<br />
syscall.Syscall(0x0, 0x3, 0xc2080c5e98, 0x10000, 0x0, 0x0, 0x0)<br />
/usr/lib64/go/src/pkg/syscall/asm_linux_amd64.s:21 +0x5<br />
syscall.read(0x3, 0xc2080c5e98, 0x10000, 0x10000, 0x0, 0x0, 0x0)<br />
/usr/lib64/go/src/pkg/syscall/zsyscall_linux_amd64.go:838 +0x75<br />
syscall.Read(0x3, 0xc2080c5e98, 0x10000, 0x10000, 0x0, 0x0, 0x0)<br />
/usr/lib64/go/src/pkg/syscall/syscall_unix.go:136 +0x5c<br />
github.com/howeyc/fsnotify.(*Watcher).readEvents(0xc2080044e0)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/howeyc/fsnotify/fsnotify_linux.go:219 +0x133<br />
created by github.com/howeyc/fsnotify.NewWatcher<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/howeyc/fsnotify/fsnotify_linux.go:126 +0x288<br />
<br />
goroutine 24 [chan receive]:<br />
github.com/howeyc/fsnotify.(*Watcher).purgeEvents(0xc2080044e0)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/howeyc/fsnotify/fsnotify.go:21 +0x51<br />
created by github.com/howeyc/fsnotify.NewWatcher<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/howeyc/fsnotify/fsnotify_linux.go:127 +0x2a0<br />
<br />
goroutine 25 [chan receive]:<br />
github.com/limetext/lime/backend.(*myLogWriter).handle(0xc208042090)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/editor.go:110 +0x70<br />
created by github.com/limetext/lime/backend.newMyLogWriter<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/editor.go:105 +0x69<br />
<br />
goroutine 26 [chan receive]:<br />
github.com/limetext/lime/backend.(*Editor).inputthread(0xc20807c000)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/editor.go:360 +0xb2<br />
created by github.com/limetext/lime/backend.GetEditor<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/editor.go:160 +0x42d<br />
<br />
goroutine 27 [select]:<br />
github.com/limetext/lime/backend.(*Editor).observeFiles(0xc20807c000)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/editor.go:432 +0x289<br />
created by github.com/limetext/lime/backend.GetEditor<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/editor.go:161 +0x448<br />
<br />
goroutine 17 [syscall]:<br />
runtime.goexit()<br />
/usr/lib64/go/src/pkg/runtime/proc.c:1445<br />
<br />
goroutine 28 [select]:<br />
code.google.com/p/log4go.func·002()<br />
/home/abuild/rpmbuild/BUILD/go/src/code.google.com/p/log4go/filelog.go:84 +0x8ac<br />
created by code.google.com/p/log4go.NewFileLogWriter<br />
/home/abuild/rpmbuild/BUILD/go/src/code.google.com/p/log4go/filelog.go:116 +0x2c4<br />
<br />
goroutine 30 [chan receive]:<br />
main.(*tbfe).renderthread(0xc2080febd0)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/frontend/termbox/main.go:369 +0x90<br />
created by main.main<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/frontend/termbox/main.go:675 +0x1cf<br />
<br />
goroutine 31 [chan receive]:<br />
github.com/limetext/lime/backend.(*View).parsethread(0xc208106900)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/view.go:236 +0x151<br />
created by github.com/limetext/lime/backend.newView<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/limetext/lime/backend/view.go:84 +0x139<br />
<br />
goroutine 33 [chan receive]:<br />
github.com/quarnster/util/text.(*SerializedBuffer).worker(0xc20805a718)<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/quarnster/util/text/serialized_buffer.go:40 +0x5e<br />
created by github.com/quarnster/util/text.(*SerializedBuffer).init<br />
/home/abuild/rpmbuild/BUILD/go/src/github.com/quarnster/util/text/serialized_buffer.go:26 +0x88<br />
</pre><br />
<br />
He will never (and you may never either) find the cause of the "panic: runtime error: invalid memory address or nil pointer dereference" problem. (In the above case, I uninstalled "go-log4go" package.)<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
* For a library: You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
* For an application: Just uninstall all Golang packages except the "go" base package and run your application. This way you can catch all the runtime dependencies.<br />
<br />
== Golang wrapper packages for C/C++ ==<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source0: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%{go_disable_brp_strip_static_archive}<br />
<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the normal shared library finding progress (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ====<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67825openSUSE:Packaging Go2014-09-16T17:46:16Z<p>MargueriteSu: /* Development repository & process */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Go software packages for openSUSE and others using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Go =<br />
<br />
Go (Golang in Debian, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Go packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Go software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name. Usually vendor and source can be extracted from its $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed at '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click branch button for any package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build inside this repository.<br />
<br />
= Dependencies (Requires) =<br />
<br />
Golang packages are static builds, so shlib resolving tool (/sbin/ldconfig) does not work.<br />
<br />
== "Pure" Golang packages ==<br />
<br />
If you skip the essential Requires (which are '''essential''' to build the package, eg. go-log4go for go-go-qml), end users will get a weird error when he runs the package. Of course the error is plain if he's a Golang coder and uses your package as a library. But if he's a newbie to Golang and just uses a Golang application like Lime Text, the error will be complicated then.<br />
<br />
So make sure always '''explicitly Requires your runtime dependencies''' and '''do tests on your real machine'''. The test is easy:<br />
<br />
You can just install the %{name}-doc package and <code>"go run xxx.go"</code> to examples provided by upstream.<br />
<br />
== Golang wrapper packages for C/C++ ==<br />
<br />
Golang wrappers for C/C++ libraries, like go-gozmq for zeromq, will use pkg-config to find its runtime C/C++ dependencies, which means if you do not have "pkg-config" and "zeromq-devel" (which provides /usr/lib64/pkgconfig/zeromq.pc) installed, gozmq will not able to detect libzmq4 library even if you have it installed. When you run examples, it will complain:<br />
<br />
$ go run client.go <br />
# command-line-arguments<br />
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lzmq<br />
collect2: error: ld returned 1 exit status<br />
<br />
So for such Golang wrappers, it may be weird, but you have to '''Requires a *-devel package'''. Usually it's the same as BuildRequires, but sometimes more than that. You have to be precise with that by running examples manually.<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source0: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%{go_disable_brp_strip_static_archive}<br />
<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the normal shared library finding progress (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ====<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSuhttps://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=67824openSUSE:Packaging Go2014-09-16T17:09:06Z<p>MargueriteSu: /* main redeclared in this block */</p>
<hr />
<div>{{Packaging_navbar}}<br />
{{Intro|The '''Packaging Go''' is a step by step introduction on how to build Go software packages for openSUSE and others using the [[Portal:Build Service|openSUSE Build Service]].}}<br />
<br />
= About Go =<br />
<br />
Go (Golang in Debian, more search engine friendly) is an expressive, concurrent, garbage collected systems programming language that is type safe and memory safe. It has pointers but no pointer arithmetic. Go has fast builds, clean syntax, garbage collection, methods for any type, and run-time reflection. It feels like a dynamic language but has the speed and safety of a static language.<br />
<br />
= Naming & Version scheme =<br />
<br />
Please note that Go packages follow a strict naming convention, i.e. 'go-$EXACT_UPSTREAM_NAME'. Furthermore, most Go software currently doesn't follow a strict version scheme. You should use the date when you retrieved the upstream software (e.g. via git/mercurial/etc. checkout) plus the VCS used, like 0.0.0+git20110521. If the upstream maintainers decide to start using a version scheme, this ensures easy package upgrades in the future.<br />
<br />
But please also note that Golang has '''many''' 3rd party implementations/wrappers for any single purpose. eg: go-check has 2 implementations, go-geoip has about 5 or 6 implementations. If you can't differentiate them using $EXACT_UPSTREAM_NAME, you may need to add '''vendor''' (like author's name) or '''source''' (github, googlecode) name. Usually vendor and source can be extracted from its $IMPORTPATH.<br />
<br />
= Development repository & process =<br />
<br />
Golang packages for openSUSE are developed under '''devel:languages:go''' repository on openSUSE Build Service.<br />
<br />
If you want to submit a package to this repository, please:<br />
<br />
* branch it (easy way: visit this repository and click branch button for any package inside this repository)<br />
* copy your package from your home repository to the branched repository<br />
* build<br />
* submit<br />
<br />
This will ensure that your package will 100% build inside this repository.<br />
<br />
= The easy and stupid way =<br />
<br />
You can use the following spec file template. Make sure to replace $VARIABLES with appropriate values. <br />
<br />
#<br />
# Copyright (c) 2014, $YOUR_NAME <$YOUR_MAIL><br />
#<br />
# All modifications and additions to the file contributed by third parties<br />
# remain the property of their copyright owners, unless otherwise agreed<br />
# upon. The license for this file, and modifications and additions to the<br />
# file, is the same license as for the pristine package itself (unless the<br />
# license for the pristine package is not an Open Source License, in which<br />
# case the license is the MIT License). An "Open Source License" is a<br />
# license that conforms to the Open Source Definition (Version 1.9)<br />
# published by the Open Source Initiative.<br />
<br />
# Please submit bugfixes or comments via http://bugs.opensuse.org/<br />
# <br />
<br />
<br />
Name: go-$EXACT_UPSTREAM_NAME<br />
Version: 0.0.0+git20140916<br />
Release: 0<br />
License: $LICENSE<br />
Summary: $SUMMARY<br />
Url: $HOMEPAGE<br />
Group: Development/Languages/Other<br />
Source0: $EXACT_UPSTREAM_NAME-%{version}.tar.bz2<br />
BuildRequires: go-devel<br />
BuildRoot: %{_tmppath}/%{name}-%{version}-build<br />
%{go_requires}<br />
%{go_provides}<br />
# The following line is only needed for (static) libraries:<br />
%{go_recommends}<br />
<br />
%description<br />
$DESCRIPTION<br />
<br />
%godoc_package <br />
<br />
%prep<br />
%setup -q -n $EXACT_UPSTREAM_NAME<br />
<br />
%build<br />
%goprep $IMPORTPATH_NAMESPACE<br />
%gobuild $IMPORTPATH_MODIFIER<br />
<br />
%install<br />
%{go_disable_brp_strip_static_archive}<br />
<br />
%goinstall<br />
%godoc<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files<br />
%defattr(-,root,root,-)<br />
%doc README LICENSE<br />
%{go_contribdir}/*<br />
<br />
%files doc<br />
%defattr(-,root,root,-)<br />
%{go_contribdir}/*<br />
<br />
%changelog<br />
<br />
= The complicated explanation =<br />
<br />
== Macros ==<br />
<br />
You can look up the provided macros in the file '''/etc/rpm/macros.go''' (when the Golang base package "go" is installed).<br />
<br />
Some common macros are explained below (But not all of the macros):<br />
<br />
=== NOTE: Some macros can not be quoted ===<br />
<br />
Usually you have already had an idea that %make equals to %{make}, just like shell scripts.<br />
<br />
This rule applies to almost every aspect of RPM packaging. But in Go packaging you have to eliminate such careless ideas from your mind.<br />
<br />
As I know, %goprep %gofix %gobuild %goinstall %godoc %gotest are macros that can not be quoted.<br />
Because they allow arguments.<br />
<br />
=== %go_ver ===<br />
<br />
It will return Golang's version like '''1.3.1'''<br />
<br />
=== %go_arch ===<br />
<br />
It will return Golang's architecture: '''i386''' or '''amd64'''.<br />
<br />
=== %go_requires ===<br />
<br />
It will '''only''' '''Requires''' go main package for your package.<br />
<br />
{{Warning|If your package needs some other packages to build, please be sure to '''manually''' add them to Requires as well as BuildRequires. Golang is static build, the normal shared library finding progress (/sbin/ldconfig) won't find dependencies for it. That is, %go_requires itself is not enough most of the times.}}<br />
<br />
=== %go_provides ===<br />
<br />
It will '''Provides''' %{name}-devel and %{name}-devel-static for your package. <br />
<br />
Unlike C/C++ packages, Golang packages don't have header files. They're static built so '''the main package is also the devel package'''.<br />
<br />
=== %go_recommends ===<br />
<br />
It will '''Recommends''' %{name}-doc sub-package for your package.<br />
<br />
Unlike the common RPM packaging, %{name}-doc is actually the source package in Golang, instead of documentation packages.<br />
<br />
=== %godoc_package ===<br />
<br />
Like %lang_package, it will create a %{name}-doc sub-package in specfile.<br />
<br />
=== %go_contribdir ===<br />
<br />
go binaries/static libraries will be installed into this directory: <br />
<br />
%{_libdir}/go/contrib/pkg/linux_%{go_arch}<br />
<br />
=== %go_contribsrcdir ===<br />
<br />
go sources will be installed into this directory:<br />
<br />
%{_datadir}/go/contrib/src/pkg<br />
<br />
=== %goprep ===<br />
<br />
This macro will prepare the build environment for Golang.<br />
<br />
You have to give an argument $IMPORTPATH to it. If you have seen some Golang specfiles, you will find something like this:<br />
<br />
%goprep gopkg.in/qml.v1<br />
%goprep github.com/howeyc/fsnotify<br />
<br />
These '''gopkg.in/qml.v1''' or '''github.com/howeyc/fsnotify''' are actually '''not URL but PATH''', although http://gopkg.in/qml.v1 is reachable (Actually it's the index for this library).<br />
<br />
%goprep will create a %{_builddir}/go/src/gopkg.in/qml.v1 directory.<br />
<br />
Then what's the purpose for this $IMPORTPATH and how to find it?<br />
<br />
It is used for importing. eg. in Golang code:<br />
<br />
import {<br />
qml gopkg.in/qml.v1<br />
}<br />
<br />
And Golang will find such library in<br />
<br />
%{go_contribsrcdir}<br />
~/go/pkg/linux_amd64/<br />
/home/abuild/rpmbuild/BUILD/go/pkg/linux_amd64/ (This only exists in OBS build environment, that is, ~/rpmbuild/BUILD/go/pkg/linux_amd64/ will not count unless you're building inside it)<br />
<br />
And you can see the examples provided by upstream to easily find the $IMPORTPATH in source tarball.<br />
<br />
=== %gofix ===<br />
<br />
TO BE UPDATED BY OTHERS. Personally I never used this macro.<br />
<br />
=== %gobuild ===<br />
<br />
It actually builds and installs the compiled Golang codes into %{_builddir}.<br />
<br />
By default it will build everything inside %{_builddir}/go/src/$IMPORTPATH, if you want to selectively build some sub-directories inside $IMPORTPATH, please install "go" package and read /etc/rpm/macros.go for $IMPORTPATH_MODIFIER arguments' usage.<br />
<br />
=== %goinstall ===<br />
<br />
It will copy the compiled codes from %{_builddir} to %{buildroot} for RPM package creation.<br />
<br />
=== %godoc ===<br />
<br />
It will scan the source directory and copy all *.go files to %{go_contribsrcdir} to create a %{name}-doc package, just like %find_lang but without arguments.<br />
<br />
=== %gotest ===<br />
<br />
It will test all Golang codes inside source directory. <br />
<br />
{{Warning|'''It will test everything including examples'''. But one common problem is that upstream sometimes only fix/update the functional codes instead of examples (Debhelper has a function to skip testing examples so upstream may be not able to find problems at all). Some examples may not compile against the new Golang or library (It triggers lots of build errors on OBS). It's your choice to disable %check or fix the examples (or even "rm -rf" them). But please be sure not to leave codes that couldn't run for our users.}}<br />
<br />
== The changes of BUILD directory layouts ==<br />
<br />
{{Warning|RPM macros for go packaging will distroy the current directory layout in %{_builddir}, so if you do things after the %goprep macro, you will not know the BUILD directory layout unless you read the /etc/rpm/macros.go definitions or this help. ALways keep this in mind.}}<br />
<br />
There're more than one derivatives for this case:<br />
* If you got a "File or directory not found" error and you want to do a "ls -l" in sections like %install.<br />
* If you want to selectively put files into %{name}-doc packages instead of putting everything upstream provides. This usually involves file addition/deletions, which further suppose you know the directory layout of the folder you are operating under.<br />
<br />
=== Why? ===<br />
<br />
Golang is a structure sensitive language. It needs such layouts to build and place build results.<br />
<br />
=== Layout after %goprep ===<br />
<br />
'''LAYOUTs before %goprep''':<br />
<br />
BUILD/%{name}-%{version}<br />
<br />
'''LAYOUTs after %goprep''':<br />
<br />
BUILD/go/src/$IMPORTPATH<br />
BUILD/%{name}-%{version} <br />
<br />
The later is a symlink to the previous path, why not '''copy'''? Because Golang need these files to be inside its layout. And RPM will always '''cd''' into BUILD/%{name}-%{version} after %build or %install.<br />
<br />
'''THERE ALWAYS A "BUT"''':<br />
<br />
But, unlike the common RPM packaging, after running the %goprep macro, you will be no longer inside BUILD/%{name}-%{version}, but in BUILD/go/src/xxx/xxx/%{name}. This annoys many people.<br />
<br />
=== Layout after %gobuild ===<br />
<br />
While after running %gobuild, you package will be installed as<br />
<br />
BUILD/go/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or <br />
<br />
BUILD/go/bin/%{name} (it depends on upstream's choice)<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running %goinstall, you package will be installed into<br />
<br />
BUILDROOT/%{_libdir}/go/contrib/pkg/linux_%{go_arch}/xxx/xxx/%{name}.a<br />
<br />
or<br />
<br />
BUILD/usr/bin<br />
<br />
=== Layout after %godoc ===<br />
<br />
After running %godoc, you package "source" will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
'''But it will only copy *.go files'''. That is, if this .go file needs some other files like *.qml to operate, you have to manually copy them into this path.<br />
<br />
=== There is no %{name} directory in %{go_contribdir} ===<br />
<br />
From previous chapters we know xxx/xxx/%{name} is not a URL but $IMPORTPATH.<br />
<br />
So some people may try to "pushd BUILDROOT/%{go_contribdir}/xxx/xxx/%{name}" and then do "ls -l" or "find" to see what's wrong.<br />
<br />
But there'll be no such directory in BUILDROOT/%{go_contribdir}/. Actually only xxx/xxx exists, %{name}.a is actually a static compiled file. And if the source have sub-directories, they will be compiled as xxx/xxx/%{name}/<sub-directory-name>.a or xxx/xxx/%{name}/<sub-directory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be complied to xxx/xxx/%{name}.a<br />
<br />
That is, you will never see anything related even if you can "cd" into the %{name} directory after build.<br />
<br />
NOTE: this only applies to BUILDROOT/%{go_contribdir}, BUILDROOT/%{go_contribsrcdir} still has the %{name} directory containing the *.go files.<br />
<br />
== Common Golang errors ==<br />
<br />
This section collects some common Golang errors for those packagers who know little about Golang.<br />
<br />
=== undefined reference to SOME_C_FUNCTION ====<br />
<br />
Golang can call functions written in pure C with a tool named cgo. If you see<br />
<br />
/*<br />
#include <stdio.h><br />
*/<br />
import "C"<br />
<br />
in a .go file, this file calls some C functions. As a qualified packager, we all more or less have some ideas about CFLAGS and LDFLAGS, thus know "undefined reference" error means the compiler couldn't find related header files or *FLAGS in C. But how could we fix such errors in Golang? Here it is:<br />
<br />
* fix for headers are pretty easy.<br />
* Here's how to fix CFLAGS and LDFLAGS:<br />
<br />
/*<br />
#include <stdio.h><br />
#cgo pkgconfig: geoip<br />
#cgo LDFLAGS: -lGeoIP<br />
#cgo CFLAGS: -xxxxxx<br />
/*<br />
<br />
=== main redeclared in this block ===<br />
<br />
Golang is a structure sensitive language. If a folder contains multiple files and those files have more than one "main" function, this error triggers. But some old go projects (eg. since Golang 1.1) still didn't put their examples files in separate folders like "examples". We know examples are some small, independent demos relying on this project, which must have a separate "main" function. so the fix is easy, just "mkdir -p" an "examples" folder and put all such files into it in <font color="red">%prep</font> section in specfile (see [[#Layout after %goprep]] chapter).<br />
<br />
=== object is [linux amd64 go1.3 X:precisestack] expected [linux amd64 go1.3.1 X:precisestack] ===<br />
<br />
This error means your package is built against go 1.3, but your current Golang environment is go 1.3.1. Usually a rebuild will solve the problem.<br />
<br />
= Team members =<br />
* [[User:Saschpe|Sascha Peilicke]]<br />
* [[User:Andtecheu|Graham Anderson]]<br />
* [[User:MargueriteSu|Marguerite Su]]<br />
<br />
= External links =<br />
* [http://go-lang.org Go Language Homepage]<br />
* [http://godoc.org/ Search for Go packages and manuals]<br />
<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]</div>MargueriteSu