https://en.opensuse.org/api.php?action=feedcontributions&user=Etorres4&feedformat=atomopenSUSE Wiki - User contributions [en]2024-03-28T21:27:17ZUser contributionsMediaWiki 1.37.6https://en.opensuse.org/index.php?title=openSUSE:Build_Service_Tutorial&diff=132506openSUSE:Build Service Tutorial2019-03-03T07:51:33Z<p>Etorres4: Fix minor typo in the .quitrc section</p>
<hr />
<div>{{Buildservice_navbar}}<br />
{{Packaging docnav}}<br />
{{Intro|This document should give an overview of the Build Service and a tutorial on how to build packages for different distributions using this great tool. We will try to show all actions on an example application so you can follow the steps to produce your own packages. }}<br />
<br />
== Prerequisites ==<br />
<br />
You should have a general understanding about [http://en.wikipedia.org/wiki/RPM_Package_Manager RPMs] and how they are created. See the [[openSUSE:Packaging_guidelines|packaging guidelines]] for openSUSE or a similar document of another supported packaging system such as [http://en.wikipedia.org/wiki/Dpkg dpkg]. This document is not meant to be a replacement for packaging documentation, which can be found at the above links.<br />
<br />
You should be familiar with the source code environment your project is using for your package. The Build Service can work around some common mistakes and will try to guide you in case of failures. We have a [http://lists.opensuse.org/archive/opensuse-buildservice/ buildservice-mailinglist] which can be a source of help and advice. However, decisions on which patches to apply, what compiler flags to use, etc. are ultimately up to you.<br />
<br />
== Requirements ==<br />
<br />
To make full use of the [http://build.opensuse.org Build Service], you need '''to login with your openSUSE/SUSE account''' (same as wiki, bugzilla...). If you have no account yet, click on the "[https://build.opensuse.org/ICSLogin/?%22https://build.opensuse.org/%22 sign up]" link at the top of the page to create one. Keep in mind that if you change your password someday that you also need to change <tt>~/.oscrc</tt> or <tt>~/.config/osc/oscrc</tt>, and if you fail to do so and run osc commands that involve the server nevertheless, the user account may be blocked after repeated tries with an incorrect password.<br />
<br />
Futhermore, if you start the build as normal user (good idea!), you will be asked for the root password of your local machine. You can avoid that if you add your user to <tt>/etc/sudoers</tt> with the following procedure:<br />
<br />
<ol><br />
<li>Run the following command:<br />
<pre>sudo /usr/sbin/visudo</pre><br />
</li><br />
<li>Add the following line and replace the placeholder LOGIN with your login name:<br />
<pre>LOGIN ALL = NOPASSWD: /usr/bin/build<br />
LOGIN ALL = NOPASSWD: /usr/bin/osc</pre><br />
</li><br />
</ol><br />
<br />
== Terminology ==<br />
<br />
The Build Service contains '''projects''' (you can [https://build.opensuse.org/project/list_all view a list of them]). Each project contains the resources needed to build one or more '''packages''' (i.e. RPMs/DEBs/etc.). These resources include source archives, patch files, spec files, etc. The output of a project is one or more '''repositories'''. A repository is an old familiar concept: simply a bunch of RPMs organized in a directory hierarchy along with some index/meta-data files that make it easy for tools like '''zypper''' to search and resolve dependencies. The repositories a project outputs correspond to the different operating system versions such as openSUSE 11.2, etc.<br />
<br />
As far as the projects that exist, there are "official" openSUSE projects that build the RPMs provided in the standard openSUSE distributions. The "factory" project is the work-in-progress project that will become the next version of openSUSE. There are also lots of area-specific projects such as [https://build.opensuse.org/project/show?project=Apache Apache] and [https://build.opensuse.org/project/show?project=network%3Atelephony network:telephony]. Finally, each user has his own "playground" project named '''home:''username'''''.<br />
<br />
RPMs tend to have lots of dependencies on other RPMs, and often these RPMs come from different projects within the Build Service. This has two important implications.<br />
<br />
First, if your package depends on some other package at runtime ("Requires"), it will often also depend on it at build time (i.e., "BuildRequires"). The Build Service does not automatically go search and find build dependencies for you (other than what is included in the standard distribution you are building for). So somehow you have to tell the Build Service where to get the required package.<br />
<br />
Secondly, a nice goal is for a repository to be '''transitively closed''', i.e. any dependency of any package in the repository is also in the repository (packages in the standard distribution excepted). This makes life easier for people installing the RPMs your project provides. But this is not required: users can always find these dependencies manually using the [http://software.opensuse.org/search search interface].<br />
<br />
The Build Service provides a few different ways to facilitate handling of these dependencies.<br />
<br />
First, you can directly add the required package(s) to your repository. This is<br />
certainly the approach you must take if no other project builds the required<br />
packages. Typically though, those packages are already being built by some<br />
other project. Consider re-using their work.<br />
<br />
The second option is to link the other project's repository to your repository.<br />
This is called '''layering'''. It is done by editing the meta-data of your<br />
project. Add the other project/repository as an additional path. This simply<br />
adds to the list of repositories in which the Build Service will search for<br />
"BuildRequires" dependencies at build time. This will allow your package's<br />
build to succeed, addressing the first problem, but it does not address the<br />
"transitively closed" goal at all: users will have to go fetch the required<br />
package themselves. However, this is a good choice when there are several<br />
dependencies from your project into another project and/or users are likely to<br />
be pulling from both repositories anyway.<br />
<br />
The third option is called '''linking''' and is a way to allow your project to re-use a package that already exists in another project. When you link a package into your project, dependent packages will be able to build, and the package will also appear in your project's repository, therefore solving both problems without duplicating any work.<br />
<br />
There are two types of linking: '''link''' and '''aggregate'''. When you<br />
'''link''', you can optionally modify the way the package is built. You can add patches, and enable the build for additional repositories. Your build<br />
of the package's RPM will have a different build number from the original<br />
project's build of it. Note, this could cause confusion for users. Really, you<br />
are building a different version of a package with the same name.<br />
<br />
Unless you need to modify the required package, you should '''aggregate'''<br />
instead of '''link'''. When you '''aggregate''', you are performing a<br />
"read-only" link. The package is not built within your project; instead, the<br />
already-built package is copied into your project from the original project. So<br />
the same RPM (with the same build number) will appear in both projects. For the<br />
user, there is less confusion because the RPMs are identical. <br />
<br />
The Build Service automatically detects changes in linked packages and triggers rebuilds of any packages depending on them.<br />
<br />
== Workflow ==<br />
<br />
The following steps outline a normal workflow to create a project and add packages to it. Of course, in a real world example you might fail at some steps and have to repeat it until it does not fail anymore. This outline is just to give you a feeling about what we are trying to achieve. <br />
<br />
We will show you two different ways if possible: <br />
* the '''[http://build.opensuse.org Web client]''' way<br />
* the '''[[openSUSE:OSC|Command line]]''' client way <br />
* An alternate method is the '''MonoOSC''' client way, explained in the [[openSUSE:MonoOSC_guide|MonoOSC guide]], so no need to duplicate.<br />
<br />
=== Step One – Login and one time Local Project setup ===<br />
<br />
If you already have an openSUSE Account, this is the easiest step.<br />
<br />
* '''Web client''': Open http://build.opensuse.org/ and use the login link on the upper right to login. After that, your home project is available by clicking on your username.<br />
<br />
* '''Command line''': At first, you have to install the command-line client on your machine. You can find osc packages for different distributions in the [http://download.opensuse.org/repositories/openSUSE:/Tools/ openSUSE-Tools] software download repository (yes: this is also a Build Service Project). Use your favorite package manager to install the osc package.<br />
<br />
Assuming that you are using openSUSE Tumbleweed, installation of the osc package looks like:<br />
<br />
zypper ar -r http://download.opensuse.org/repositories/openSUSE:/Tools/openSUSE_Factory/openSUSE:Tools.repo<br />
zypper in osc<br />
<br />
Afterwards, <tt>cd</tt> into the directory you want to use for your project files. Now everybody familiar with [[wikipedia:en:Apache_Subversion|SVN]] will feel "at home": try to checkout your home project using <br />
cd <directory_to_contain_project_root><br />
osc checkout home:&lt;username&gt;<br />
cd home:&lt;username&gt; <br />
: (please replace <tt>&lt;username&gt;</tt> with your login). <br />
<br />
* You will be prompted for '''your username and password''' — afterwards, osc will try to checkout packages in your home project and create a new directory called <tt>home:&lt;username&gt;</tt>. <br />
* You can edit your settings in the file <tt>~/.oscrc</tt> or <tt>~/.config/osc/oscrc</tt>. <br />
* If you enter '''wrong password''' you need to delete the whole api section for the service with wrong password for osc to ask for password again. <br />
* If you set '''<tt>plaintext_passwd = 0</tt>''' and delete the api section osc asks for username and password again and stores the password base64 encoded. It can be decoded easily but is not seen at a glance. <br />
* If you want to use multiple build services (or '''service other than https://api.opensuse.org''') use the -A option. You can shorten the <tt>-A</tt> argument by setting <tt>aliases</tt> option in the api section. You can also write a my_buildservice script saying something like <tt>exec osc -A https://api.my.build.server "$@"</tt><br />
<br />
=== Step Two – Create & Upload packages ===<br />
<br />
You can use your home project as a "playground" to test packages which will be transferred to other, more visible projects if everything is alright.<br />
<br />
* '''Web client''': On the right side click on "Home Project" to open your home project, then click on "Users" and then "Add user" to add yourself as a maintainer. After that, click on "create new package" in the packages tab. You should fill out the following three textfields: "Name" (mandatory), "Title" and "Description". Just use the package name as "Name", the package summary as "Title" and the package description as "Description". <br />
** After the package is created, go to the "Sources" tab to add the files for your package. You need to upload the source code of your package and at least a spec file (see also [[openSUSE:Packaging_guidelines|packaging guidelines]]).<br />
<br />
* '''Command line''':<br />
osc meta pkg -e home:&lt;username&gt; &lt;packagename&gt;<br />
<br />
osc will open a template xml file in your favorite editor (based on the <tt>EDITOR</tt> environment variable) and you can just add the same things (Name, Title and Description) as described above.<br />
<br />
Now call:<br />
osc co home:&lt;username&gt; &lt;packagename&gt; <br />
<br />
To add files via the command line, just cd into the project directory, copy the relevant files (typically a .tar.xz and support files).<br />
<br />
openSUSE RPM packages have their build instructions in a specfile.<br />
See the [[openSUSE:Packaging_guidelines|packaging guidelines]] how to create this. An easier approach is to copy and adapt a specfile from a similar package, or from within the tar-ball, if available.<br />
When the files are ready call<br />
osc add *<br />
this will mark the files in the directory for the next submit. To submit the files, call<br />
osc commit<br />
A commit automatically triggers the build process. You may want to delay the commit, until after you successfully built the package locally, see below.<br />
<br />
=== Step Three – Choose build targets ===<br />
<br />
Now you have to select for which distributions (e.g. openSUSE 13.1, Ubuntu 14.04 etc.) your packages should get built. <br />
<br />
* '''Web client''': Go to the "Repositories" tab on your project, and click on ''Add repositories'' and choose one of the available distributions and architectures.<br />
<br />
* '''Command line''': first get a list of available repositories<br />
osc ls<br />
then edit your project metadata:<br />
osc meta prj -e home:&lt;username&gt;<br />
and add the repository like:<br />
<br />
<repository name="openSUSE_Factory"><br />
<path project="openSUSE:Factory" repository="standard" /><br />
<arch>x86_64</arch><br />
<arch>i586</arch><br />
</repository><br />
<br />
'''project''' can be openSUSE:Factory, openSUSE:13.1, SUSE:SLE-11:SP3 and the like. The <code>repository="standard"</code> is just for future extensions (forks of a repository).<br />
<br />
=== Step Four – Build your package ===<br />
<br />
Your package is scheduled for build automatically after it is committed or some files have changed. If a required package is rebuilt, your package will automatically be rebuilt, too. <br />
<br />
You can also manually trigger a rebuild if you need: <br />
osc rebuildpac <project> <package> [<repo> [<arch>]]<br />
With the optional <code><repo></code> and <code><arch></code> arguments, the rebuild can be limited to a certain repository or architecture.<br />
<br />
If your project is named home:username, you can now find your project at http://download.opensuse.org/repositories/home:/username/<br />
<br />
==== Build your package locally ====<br />
<br />
Sometimes, it can be faster to build your package on your local machine instead of waiting for the results from the Build Service. <br />
<tt>osc</tt> supports local builds of your package if your local hardware supports it (on x86_64 you can build for i586 and x86_64, on i586 only for i586). <br />
<br />
===== Ensure you have the latest sources =====<br />
<br />
Use <tt>osc checkout</tt> (<tt>osc co</tt>) or <tt>osc up</tt> to ensure you have the latest version of the source.<br />
<br />
If it is project/package you havn't checkout at all:<br />
<br />
cd <your_obs_working_dir><br />
osc co <project> <package><br />
cd <project>/<package><br />
<br />
or a new package of an existing checked out project<br />
<br />
cd <your_obs_working_dir>/<project><br />
osc co <package><br />
cd <package><br />
<br />
or enter an existing local copy of the package and update<br />
<br />
cd <your_obs_working_dir>/<project>/<package><br />
osc up<br />
<br />
===== Perform the local build =====<br />
<br />
osc build <platform> <arch> <specfile> [--clean|--noinit]<br />
for example<br />
~/obs/home:user/my_project/my-package # osc build openSUSE_Leap_42.1 x86_64 my-package.spec<br />
<br />
<tt>osc</tt> will connect to the OBS repository server and download all needed RPMs to <tt>/var/tmp/osbuild-packagecache/''plattform''/''repository''/''arch''</tt> as cache directory. If you want to avoid network traffic, its possible to fill the cache beforehand with rpms from a DVD or iso. For that, copy the rpms from the DVD to the cache dir. <br />
<br />
<TT >osc</TT > will create a chroot environment in <TT >/var/tmp/build-root/</TT > and start the build of your package. If you only have minor changes, you can avoid the re-creation of the build environment with the option <TT >--noinit</TT >. If you suspect that your chroot environment is broken, you can trigger a complete rebuild with the option <TT >--clean</TT >. You can configure the chroot directory; see the comments in your <TT >~/.oscrc</TT > or <tt>~/.config/osc/oscrc</tt> file.<br />
<br />
{{Info|<TT >osc</TT > will refuse to install packages from projects your system does not trust. This may happen when your package is linked to a development project and your system is not configured to use that repository. You can get the necessary GPG key by executing:<br><br><br />
<br />
sudo rpm --import - <<_END_KEY<br />
$(osc signkey <VAR >offending-project</VAR >)<br />
_END_KEY<br />
}}<br />
<br />
After your packages are built in this chroot environment, you can find the resulting packages in <tt>/var/tmp/build-root/home/abuild/rpmbuild/RPMS/</tt> (older versions of rpmbuild use <tt>/usr/src/packages/RPMS/</tt>.<br />
<br />
If your package uses a URL download service, you may have to execute the following command first:<br />
<br />
zypper ar -r http://download.opensuse.org/repositories/openSUSE:/Tools/openSUSE_11.3/openSUSE:Tools.repo<br />
<br />
The complete log file of your local build is stored in ''/var/tmp/build-root/.build.log''.<br />
<br />
===== Correct Errors in the Local Build Process =====<br />
<br />
The main reason why you would need to compile a new package for openSUSE or any other distro is to assert compatibility if your package has not yet been compiled for your operating system version and release. <br />
However, that way you may encounter new errors in the build process which need to be fixed.<br />
The easiest way to fix errors is to chroot to the build environment and create a fix there. You may want to use [http://www.elstel.com/openroot openroot] instead of chroot in order to get X11 access and all the other necessary directories mounted.<br />
<br />
osc chroot openSUSE_12.1 x86_64<br />
<br />
or old-fashioned and cumbersome<br />
<br />
chroot /var/tmp/build-root/<br />
cd /home/abuild/rpmbuild/BUILD/your-package-dir<br />
ls<br />
or:<br />
openroot /var/tmp/build-root/ 'cd /home/abuild/rpmbuild/ILD/your-package-dir; ls; bash'<br />
...<br />
exit<br />
<br />
===== Dependencies =====<br />
If you get a dependency error during your build, add a line containing the build dependencies, like:<br />
BuildRequires: cmake libkde4-devel<br />
In this case, cmake and libkde4-devel will be installed before your package is built.<br />
<br />
===== Install extra packages to build root =====<br />
For debugging purposes, you might need to install extra packages to your local build root to debug and fix build related problems. This can be done through the '''~/.oscrc''' file and variable '''extra-pkgs'''. For example:<br />
<br />
extra-pkgs = vim gdb strace valgrind<br />
<br />
===== Install privileges =====<br />
If you get an error message like this:<br />
error: Bad exit status from /var/tmp/rpm-tmp.qrRAn2 (%install)<br />
this means that your %install step has failed (and all others before went well). This can be because of missing write privileges if you try to install to the wrong place. In this case add the following make install command to your spec file:<br />
make install DESTDIR=%buildroot<br />
<br />
===== Submit your work back to OBS =====<br />
Once you have your <tt><package></tt> directory the way you want it, use the below commands to submit your work back to OBS.<br />
<br />
add a new file to the package<br />
osc add <br />
<br />
remove a file from the package<br />
osc rm <br />
<br />
update the [[openSUSE:Creating_a_changes_file_(RPM)|change log]] (ie. *.changes)<br />
osc vc <br />
<br />
submit your updated files back to OBS<br />
osc commit <br />
<br />
==== Patches ====<br />
<br />
There are several ways how to create a new patch. For instance you can use a simple tool called diff or advanced tool quilt. For more information about patches visit [[openSUSE:Packaging_Patches_guidelines|patches guidelines]].<br />
<br />
===== Using diff =====<br />
If you plan to patch a file, copy it before editing to .orig, retry the desired step in the build process until it succeeds and then create a patch for it. <br />
<br />
To make the build more verbose you may want to insert a <tt>set -x</tt> in your specfile making bash recite all executed commands (<tt>set +x</tt> disables reciting afterwards).<br />
<br />
<source lang="bash"><br />
diff -Pdpru /var/tmp/build-root/home/abuild/rpmbuild/BUILD/your-package-dir/Makefile.orig \<br />
/var/tmp/build-root/home/abuild/rpmbuild/BUILD/your-package-dir/Makefile \<br />
>/osc/home:user/your-package-dir/my.patch<br />
</source><br />
<br />
Now add the patch to the specfile by listing <tt>Patch67: my.patch</tt> (where 67 is usually replaced by the lowest unoccupied number of the patch) in the header. Then let it be applied at the appropriate position (usually <tt>%setup</tt>) in the build process by <tt>%patch67 -p7</tt> (-p7 strips seven directory levels if you have not manually edited the file directories in the header of the patch file).<br />
<br />
===== Using quilt =====<br />
You may find it easier to use a special program for automatic patch generation like quilt:<br />
<br />
<source lang="bash"><br />
osc co yourproject/yourpackage<br />
cd yourproject/yourpackage<br />
quilt setup -v *spec<br />
cd yourpackage-*/<br />
quilt push -a # apply old patches<br />
quilt new yourpackage-version_fixbuild.patch<br />
quilt edit src/foo.c<br />
quilt refresh<br />
</source><br />
<br />
<code>foo-fixbuild.patch</code> will automatically be created in the parent dir. If you work on a package which doesnt have a patch yet. You have to remember to copy the patch from the patch directory to your package directory. Rerun <code>quilt setup</code> to get an initial patch. You can remove patches from your working copy with <code>quilt pop</code>.<br />
<br />
An example <tt>.quiltrc</tt> file:<br />
<source lang="bash"><br />
# Options passed to GNU diff when generating patches<br />
QUILT_DIFF_OPTS="--show-c-function" <br />
# QUILT_DIFF_OPTS="" <br />
# Options passed to GNU patch when applying patches<br />
#QUILT_PATCH_OPTS="--ignore-whitespace --unified-reject" <br />
<br />
# Options to pass to commands (QUILT_${COMMAND}_ARGS)<br />
QUILT_PUSH_ARGS="--color=auto" <br />
QUILT_DIFF_ARGS="--color=auto" <br />
QUILT_REFRESH_ARGS="--backup -p0"<br />
QUILT_PATCH_OPTS="--unified-reject-files --backup"<br />
</source><br />
<br />
=== Step Five: Check the logfiles ===<br />
<br />
The buildservice produces one big logfile for each build of a package.<br />
<br />
* '''Web client''': Just click on the status of the ''Build result'' tab in the package view.<br />
<br />
* '''Command line''': You have a few choices depending on your needs (<code>project</code> and <code>package</code> are optional if you are in the package directory):<br />
<br />
osc prjresults [<project>]<br />
<br />
Shows the aggregated build results of an entire project. Or you can do:<br />
<br />
osc results [<project> <package>]<br />
<br />
Shows the build results of a single package.<br />
<br />
osc buildlog <platform> <arch><br />
<br />
Shows the log file from a package (you need to be inside a package directory).<br />
<br />
===Create Patterns===<br />
Since Code12 (SLES-12/openSUSE-13.2) we utilize a new method of defining patterns, as opposed to the older XML-based patterns files. A pattern and it's dependencies are now represented by a rpm package. The few pattern specific properties are provided by this patterns-package. No extra XML-file is needed.<br />
<br />
Some more details about the patterns-packages can be found [https://doc.opensuse.org/projects/libzypp/HEAD/zypp-pattern-packages.html here] and in the project [https://build.opensuse.org/package/show/system:install:head/patterns-openSUSE obs://build.opensuse.org/system:install:head/patterns-openSUSE] maintaining the openSUSE patterns.<br />
<br />
'''OBSOLETE SINCE SLES-12/openSUSE-13.2: The part below refers to the old way od defining patterns with XML-files:'''<br />
<br />
Patterns are files which contain a list of packages together with a description of what they are useful for. Additionally the Build Service creates .ymp files for each generated repository pattern. These .ymp files can be used for a [[openSUSE:One_Click_Install_specification|One Click Install]] by the user. <br />
<br />
In short, patterns are useful for installing a set of software for a typical need without creating dependencies between packages.<br />
<br />
Submitting patterns is possible using the api directly, or using osc:<br />
<br />
* to open a pattern in $EDITOR (creating it if it doesn't exist yet)<br />
osc meta pattern -e <project> <pattern><br />
* to list existing patterns<br />
osc meta pattern <project><br />
* get an existing pattern<br />
osc meta pattern <project> <pattern><br />
* You can also submit an existing file as below:<br />
osc meta pattern --file <local_file> <project> <pattern><br />
<br />
To test: clicking on the .ymp in konqueror should launch the installer, if you do not have konqueror installed, you can try launching from shell as normal user:<br />
/sbin/yast2 MetaPackageHandler http://download.opensuse.org/repositories/<project>/<SUSE_Factory or openSUSE_10.2>/<pattern>.ymp<br />
<br />
The following file is an example pattern file from the KDE:KDE4 project. You can see the generated .ymp file from it [http://download.opensuse.org/repositories/KDE:/KDE4:/Factory:/Desktop/openSUSE_Factory/KDE4-GAMES.ymp here].<br />
<pre><br />
<pattern<br />
xmlns="http://novell.com/package/metadata/suse/pattern"<br />
xmlns:rpm="http://linux.duke.edu/metadata/rpm"<br />
><br />
<name>KDE 4 Games</name><br />
<summary>KDE 4 Games</summary><br />
<description>A number of games for KDE 4.</description><br />
<uservisible/><br />
<category lang="en">Desktop Functions</category><br />
<rpm:recommends><br />
<rpm:entry name="kde4-kpat"/><br />
<rpm:entry name="kde4-kmahjongg"/><br />
<rpm:entry name="kde4-kmines"/><br />
<rpm:entry name="kde4-kreversi"/><br />
<rpm:entry name="kde4-ksudoku"/><br />
</rpm:recommends><br />
<rpm:suggests><br />
<rpm:entry name="kde4-katomic"/><br />
<rpm:entry name="kde4-kbattleship"/><br />
<rpm:entry name="kde4-ksquares"/><br />
<rpm:entry name="kde4-bovo"/><br />
<rpm:entry name="kde4-kiriki"/><br />
<rpm:entry name="kde4-kwin4"/><br />
<rpm:entry name="kde4-kolf"/><br />
<rpm:entry name="kde4-klines"/><br />
<rpm:entry name="kde4-ksame"/><br />
<rpm:entry name="kde4-lskat"/><br />
<rpm:entry name="kde4-kgoldrunner"/><br />
<rpm:entry name="kde4-kblackbox"/><br />
<rpm:entry name="kde4-kbounce"/><br />
<rpm:entry name="kde4-ktuberling"/><br />
<rpm:entry name="kde4-knetwalk"/><br />
<rpm:entry name="kde4-kjumpingcube"/><br />
<rpm:entry name="kde4-kspaceduel"/><br />
<rpm:entry name="kde4-konquest"/><br />
<rpm:entry name="kde4-kshisen"/><br />
</rpm:suggests><br />
</pattern><br />
</pre><br />
<br />
Some Tag descriptions:<br />
{| border="1" cellpadding="5" cellspacing="0"<br />
! Tag !! Description<br />
|-<br />
| <pre><rpm:requires><br />
<rpm:entry name="example" /><br />
</rpm:requires></pre> || '''Requires''' RPM ''example'': this package must be installed - otherwise the pattern is not fulfilled.<br />
|-<br />
| <pre><rpm:recommends><br />
<rpm:entry name="example" /><br />
</rpm:recommends></pre> || '''Recommends''' RPM ''example'': if available and all dependencies of this package are fulfilled, the package would be installed. If the package is not available, there are not error messages. If the package dependencies are not met, the package would be visible but not installed. <br />
|-<br />
| <pre><rpm:suggests><br />
<rpm:entry name="example" /><br />
</rpm:suggests></pre> || '''Suggests''' RPM ''example'': would be shown in the pattern but not installed per default<br />
|}<br />
<br />
== A start to end example of a simple change ==<br />
<br />
{{Info|'''Note:''' There are at least two other wiki pages that document the branch/fix/submit patch workflow:<br />
* [[openSUSE:Fixing_bugs]]<br />
* [[openSUSE:Package maintenance]]<br />
<br />
The goal here is to have a specific example that can be used as a tutorial.<br />
}}<br />
<br />
<br />
<br />
{{Warning|DRAFT BELOW, not yet finished or tested}}<br />
<br />
A common activity is to branch an existing package in an existing project, make a change and submit that change back to the original package.<br />
<br />
The basic steps are:<br />
<br />
# Branch the original package: <tt>osc branch &lt;original_project&gt; &lt;original_package&gt;</tt> This creates a new branch project that is specific for you named <tt>home:&lt;your_user_name&gt;:branches:&lt;original_project_name&gt;</tt> and therein it creates a new package with the same name as original package that is basically a copy of the original package.<br />
# Checkout the branched package: <tt>osc checkout home:&lt;your_user_name&gt;:branches:&lt;original_project_name&gt;/&lt;original_package_name&gt;</tt> This downloads the source files of the branched package from the server into a local sub-directory named <tt>home:&lt;your_user_name&gt;:branches:&lt;original_project_name&gt;/&lt;original_package_name&gt;</tt><br />
# Go to the local sub-directory: <tt>cd home:&lt;your_user_name&gt;:branches:&lt;original_project_name&gt;/&lt;original_package_name&gt;</tt> and set the usual default umask <tt>umask 0022</tt><br />
# Work on your local copy of the package until it works for you:<br />
## Change the local source files (e.g. edit the specfile or create a patch)<br />
## Perform a local build <br />
## Do a local package installation<br />
## Test the local installed package<br />
# Update the changes file: <tt>osc vc</tt> This opens an editor (usually 'vi') and creates an appropriate header for a RPM changes entry. If there was a bug report it must be referenced as bnc#123456<br />
# If you added new files (e.g. new patches) or removed files (e.g. obsolete patches), update the version control status of the local source files: <tt>osc addremove</tt> and verify with <tt>osc status</tt> that there are no files with problematic version control status like '?' or '!'<br />
# Commit the local source files into the branched package: <tt>osc commit</tt> This uploads the local source files into the branched package on the server and that triggers an automated re-build of the branched package.<br />
# Review the build results of the branched package for all build repositories that are enabled for the original package: <tt>osc results --verbose home:&lt;your_user_name&gt;:branches:&lt;original_project_name&gt; &lt;original_package_name&gt;</tt> To list the build repositories that are enabled for the original package get its build results: <tt>osc results &lt;original_project&gt; &lt;original_package&gt;</tt><br />
# If the re-build of the branched package "succeeded" for all build repositories that are enabled for the original package, create a request to submit the branched package back to the original package: <tt>osc submitrequest --message='&lt; a short message that describes what you changed plus bnc#123456 if there exists a matching bug report&gt;' home:&lt;your_user_name&gt;:branches:&lt;original_project_name&gt; &lt;original_package_name&gt; &lt;original_project&gt; &lt;original_package&gt;</tt> and remenber the request ID number.<br />
# From time to time check what happened with your request: <tt>osc request show &lt;request_ID_number&gt;</tt> If you need to get in direct contact with the maintainers of the original package: <tt>osc maintainer &lt;original_project&gt; &lt;original_package&gt;</tt> shows their user names and <tt>osc whois &lt;user_name&gt;</tt> shows fullname and email of a buildservice user.<br />
<br />
It's a few steps, but once you get a hang on it, it becomes second nature.<br />
<br />
This assumes you already have an account on OBS. If not, go ahead and set that up at http://build.opensuse.org/ and use the login link on the upper right to login. OBS uses the same authentication system as the rest of the openSUSE infrastructure like bugzilla, so you likely all ready have a account, you just need to login for the first time and the OBS account home project will be automatically created.<br />
<br />
Here's a real example:<br />
<br />
One time setup from the command line<br />
sudo zypper in osc<br />
mkdir ~/obs<br />
<br />
Then you need to branch a local copy of a package.<br />
cd ~/obs<br />
umask 0022<br />
osc branch security:forensics sleuthkit<br />
osc co home:<your_user_name>:branches:security:forensics/sleuthkit<br />
cd ~/obs/home:<your_user_name>:branches:security:forensics/sleuthkit<br />
<br />
Now that you have an existing package already, it's as easy as:<br />
# this untars the tarball and does some magic<br />
quilt setup sleuthkit.spec<br />
# chdir to sources<br />
cd sleuthkit-3.2.3<br />
# apply all patches<br />
quilt push -a<br />
# add new patch<br />
quilt new testing.patch<br />
# add a file to the patch<br />
quilt add some-file<br />
vi <some-file><br />
# or alternatively:<br />
quilt edit <some-file><br />
# and finally<br />
quilt refresh -p1<br />
# copy the patch up to the project dir<br />
cp patches/testing.patch .. <br />
# and now handle the spec file<br />
cd ..<br />
vi sleuthkit.spec<br />
# Add patch to it by creating a Patch0 entry in the header area and a %patch0 -p1 line to the %prep section<br />
<br />
# tell OBS that the package now includes a new file<br />
osc add testing.patch<br />
# update the changes file<br />
osc vc -m "Fix some typos."<br />
# and build, install and test your work<br />
osc build<br />
# perform a local install. At the end of the osc build output the full path of the RPM file should be shown<br />
zypper in -f <full_path_to_rpm><br />
# repeat until happy. Go back to quilt edit if not happy.<br />
# send your edits back to OBS<br />
osc commit<br />
# wait a period of time for new packages to build on OBS<br />
# check the build status via the WebUI for your branched package<br />
# Once published, install the RPM from OBS and test again<br />
# submit your changes back to the original package. If there is a bugzilla entry, be sure to reference it<br />
<br />
When your done testing, submit the change back to the original package you branched<br />
osc sr<br />
<br />
== See also ==<br />
<br />
* [[openSUSE:Build_Service_Tips_and_Tricks|General Tips and Tricks for the buildservice]]<br />
* [[openSUSE:Build_Service_Collaboration|How to contribute to a package maintained by someone else]]<br />
* [[openSUSE:Build_Service_cross_distribution_howto|Cross distribution package how to]]<br />
* [[openSUSE:OSC_plugins|Writing osc plugins]]<br />
* [[openSUSE:Build_Service_Debian_builds|Sharing Debian packages]]<br />
<br />
[[Category:Build Service|Tutorial]]<br />
[[Category:Packaging]]<br />
[[Category:Packaging documentation]]<br />
<br />
[[de:openSUSE:Build Service Anleitung]]<br />
[[el:openSUSE:Build Service Tutorial]]<br />
[[es:Build Service/Guía_básica]]<br />
[[fr:Build Service/Tutoriel]]<br />
[[it:openSUSE:Build Service Tutorial]]<br />
[[ja:openSUSE:Build Service チュートリアル]]<br />
[[ru:openSUSE:Руководство_по_использованию_службы_сборки]]<br />
[[zh:SDB:编译服务教程]]</div>Etorres4https://en.opensuse.org/index.php?title=openSUSE:Package_dependencies&diff=130736openSUSE:Package dependencies2018-12-11T00:10:28Z<p>Etorres4: /* BuildArch */</p>
<hr />
<div>{{Packaging docnav}}<br />
=Package Dependencies=<br />
==Requires==<br />
RPM has very good capabilities of automatically finding dependencies for libraries, Perl modules, etc. There is usually no need to explicitly list "Requires:" (e.g. <code>Requires: libqt4</code>) when the dependency has already been picked up by RPM in the form of depending on shared libraries in the libqt4 package.<br />
<br />
If your package splits into sub-packages, they may need to require the base package using a versioned dependency.<br />
<br />
Requires: %{name} = %{version}<br />
<br />
<code>-devel</code> sub-packages need to explicitly depend on packages with the shared libraries that the devel package has symlinks to. For example, libfoobar-devel needs:<br />
<br />
Requires: libfoo2 = %{version}, libbar5 = %{version}<br />
<br />
See [[Libzypp/Dependencies]] for a list of dependency and resolvable types.<br />
<br />
==PreReq==<br />
<br />
PreReq is a hack; it is a high-priority "Requires" and is normally only required for breaking circular dependencies when unforgiving scriptlets are involved. Almost always, the regular Requires, Requires(pre), Requires(post), etc. work and should be used instead.<br />
<br />
==BuildArch==<br />
Typical usage:<br />
<br />
BuildArch: noarch<br />
<br />
Use this with your package, if you have no architecture dependent files in your file list. <br />
<br />
Note that all subpackages must be also <code>noarch</code>, if your main package is <code>noarch</code>.<br />
<br />
==BuildRequires==<br />
'''You must explicitly list the packages that your package requires to build successfully.'''<br />
<br />
Unlike with ''Requires'', for BuildRequires there is no automatic procedure to find dependencies. Having proper build requirements saves the time of all developers and testers because they will not need to search for missing build requirements manually. It also ensures that the build is reproducible and uses always the same features. ''configure'' scripts, for example, may exclude PNG support depending on the availability of libpng in the build system. With <code>BuildRequires: libpng-devel</code> (or since openSUSE 11.4: <code>BuildRequires: pkgconfig(libpng14)</code>, you ensure that the build will fail if libpng is not present.<br />
<br />
===OBS Caveat===<br />
Conditional BuildRequires are limited to simple variables. RPM usually supports complex constructs like this in an %if expression:<br />
<br />
%if 0%(test "%something" = "enabled" && echo 1)<br />
<br />
But when evaluating BuildRequires, the RPM parser of the BuildService runs in an environment where subshell expansions are disabled. You'll see warnings like this:<br />
<br />
Warning: spec file parser line 109: can't expand %(...)<br />
<br />
%lua scripts are not interpreted by the dispatcher either; no warning is emitted.<br />
<br />
The following example uses only a simple variable, which works with BuildRequires:<br />
<br />
%if ! %{with own_mpfr}<br />
BuildRequires: mpfr-devel<br />
%endif<br />
<br />
===Exceptions===<br />
There is no need to include the following packages or their dependencies as BuildRequires, because they would occur too often. These packages are considered the minimum build environment.<br />
<br />
Also try this command for a list:<br />
{{shell|osc meta prjconf openSUSE:Factory &#x7c; egrep '^(Preinstall:&#x7c;Support:&#x7c;Required:)'}}<br />
<pre>Preinstall: aaa_base acl attr bash coreutils diffutils<br />
Preinstall: filesystem fillup glibc grep insserv libacl libattr<br />
Preinstall: libbz2-1 libgcc%{gcc_version} libxcrypt m4 libncurses5 pam<br />
Preinstall: permissions libreadline6 rpm sed tar zlib libselinux1<br />
Preinstall: liblzma5 libcap2 libpcre0<br />
Preinstall: libpopt0 libelf1 liblua5_1<br />
Required: gcc gcc%{gcc_version} glibc perl rpm tar patch<br />
Support: autoconf automake binutils bzip2 gcc gcc%{gcc_version}<br />
Support: gettext-runtime glibc libtool perl rpm zlib<br />
Support: libncurses5<br />
Support: libaudit1 cpio cpp cpp%{gcc_version} cracklib cvs<br />
Support: file findutils gawk gdbm gettext-tools<br />
Support: glibc-devel glibc-locale groff gzip info less<br />
Support: libbz2-devel libdb-4_8<br />
Support: libstdc++%{gcc_version}<br />
Support: udev<br />
Support: libxcrypt libzio<br />
Support: linux-glibc-devel make man netcfg<br />
Support: net-tools pam-modules patch perl-base sysvinit-tools<br />
Support: texinfo timezone util-linux libmount1 login<br />
Support: libgomp%{gcc_version} libuuid1 psmisc<br />
Support: terminfo-base update-alternatives pwdutils build-mkbaselibs<br />
Support: brp-check-suse post-build-checks rpmlint-Factory<br />
Support: build-compare<br />
Support: libunwind libunwind-devel<br />
</pre><br />
<br />
==Conflicts==<br />
Whenever possible, openSUSE packages should avoid conflicting with each other. Unfortunately, this is not always possible. For full details on openSUSE Conflicts policy, see [[openSUSE:Packaging conflicts]].<br />
<br />
==Recommends==<br />
SUSE's RPM supports the Recommends tag, but it was not available upstream until very recently. As a result, packages with Recommends will fail to build for OBS targets Fedora_18, RHEL_6 and CentOS_6, for example. A workaround is to exclude the Recommends tag from non-SUSE targets:<br />
<br />
%if 0%{?suse_version}<br />
Recommends: foo<br />
%endif<br />
<br />
Alternatively the Recommends tag could become a Requires tag so that a recommended package (foo) gets installed in any case on systems that do not support RPM Recommends:<br />
<br />
%if 0%{?suse_version}<br />
Recommends: foo<br />
%else<br />
Requires: foo<br />
%endif<br />
<br />
See also [[openSUSE:Build Service cross distribution howto]]<br />
<br />
==File Dependencies==<br />
RPM gives you the ability to depend on files instead of packages. Whenever possible, you should avoid file dependencies outside of <code>/etc</code>, <code>/bin</code>, <code>/sbin</code>, <code>/usr/bin</code>, or <code>/usr/sbin</code>. Using file dependencies outside of those directories requires yum (and other depsolvers using the repomd format) to download and parse a large XML file looking for the dependency. Helping the depsolvers avoid this processing by depending on the package instead of the file saves our end users a lot of time. There are times when other technical considerations outweigh these considerations. One specific example is packages installing into <code>%{_libdir}/mozilla/plugins</code>. In this case, mandating a specific browser in your package just to own this directory could drag in a large amount of needless packages. Requiring the directory to resolve the dependency is the better choice.<br />
<br />
----<br />
<br />
= How to do distribution upgrades =<br />
<br />
There are two ''update modes'' which need different behaviour<br />
# Bugfixes (Patches)<br />
# Distribution upgrade<br />
<br />
In the first mode, installed packages are patched in order to fix bugs or to introduce<br />
missing functionality. However, the package version usually stays since the pristine tarball is the same; only the package release number is changed.<br />
<br />
Also, the ''build environment'' (compiler, libraries, etc.) only sees minimal changes.<br />
<br />
Distribution upgrade lifts the complete system to a new level and the operating system version gets increased.<br />
(If the system is e.g. openSUSE 10.2, it will increase to openSUSE 10.3)<br />
The package changes allowed during distribution upgrade can be much more severe and include<br />
* dropped packages<br />
* new packages<br />
* renamed packages<br />
* merged packages<br />
* splitted packages<br />
Such changes are hard (or even impossible) to express by RPM dependencies. Thus, a more<br />
expressive form of package dependencies is needed so the system upgrade can be performed.<br />
<br />
This Wiki page documents how to express dependencies for distribution upgrade.<br />
<br />
If you are adding dependencies for seamless system upgrade, do not forget to specify the<br />
openSUSE version for which these are required. It will allow to recognize these lines<br />
as obsolete in future versions (most probably it would be openSUSE version + 1 and<br />
SLE version + 2).<br />
<br />
<br />
=== Means to express dependencies ===<br />
Each package can express dependencies on other packages by defining symbolic<br />
names for <tt>Provides</tt>, <tt>Requires</tt>, and <tt>Conflicts</tt>.<BR><br />
These symbolic names are usually names of packages but can also be “abstract”<br />
names not related to a package.<br />
<br />
These symbolic names can be used to express ''capabilities'' which are unrelated<br />
to a specific package. For example, the capability '''MTA''' (mail transport agent)<br />
is provided by multiple packages, <tt>sendmail</tt> and <tt>postfix</tt> being<br />
the most prominent.<br />
<br />
It is important to remember that all symbolic names (being package or<br />
abstract names) reside in the same ''namespace''. When choosing an abstract<br />
name (e.g. for a capability), it must not conflict with another package name.<br />
<br />
To express update dependencies in order to replace one (old) package with<br />
another (newer) package, the <tt>Obsoletes</tt> tag is used.<br />
<br />
=== Facts for RPM dependencies ===<br />
<br />
* Each package implicitly provides its name.<br>There is no need to provide the package name, but other packages can require (or conflict with) the package name.<br />
* A package can not conflict with a symbolic tag it provides.<br>Since the package name is provided implicitly, a package can not conflict with itself.<br />
* <tt>Obsolete</tt> works on real package names only.<br>One can not obsolete a symbolic tag.<br />
* Symbolic names, as used in <tt>Requires</tt>, <tt>Provides</tt> and <tt>Conflicts</tt> are case-sensitive.<br />
<br />
== Basic dependencies ==<br />
<br />
=== Installing a new package ===<br />
<br />
[[Image:New.png]]<br />
<br />
{|style="background:#d9e5bf;font-size:100%; border:1px solid #aaa;" border="1" cellpadding="2" cellspacing="3" <br />
!style="background:#669900;color:#fff"| pac.spec<br />
!style="background:#669900;color:#fff"|<br />
|-<br />
| Name:<br />
| pac<br />
|-<br />
| Version:<br />
| 1.0<br />
|-<br />
| Requires:<br />
|-<br />
| Provides:<br />
|-<br />
| Obsoletes:<br />
|-<br />
| Conflicts:<br />
|-<br />
|}<br />
<br />
=== Updating a package ===<br />
<br />
[[Image:Update.png]]<br />
<br />
{|style="background:#d9e5bf;font-size:100%; border:1px solid #aaa;" border="1" cellpadding="2" cellspacing="3" <br />
!style="background:#669900;color:#fff"| pac.spec<br />
!style="background:#669900;color:#fff"|<br />
|-<br />
| Name:<br />
| pac<br />
|-<br />
| Version:<br />
| 1.1<br />
|-<br />
| Requires:<br />
|-<br />
| Provides:<br />
|-<br />
| Obsoletes:<br />
|-<br />
| Conflicts:<br />
|-<br />
|}<br />
<br />
The matching name and the higher version make this an update for <tt>pac-1.0</tt>.<br />
<br />
=== Renaming a package ===<br />
<br />
[[Image:Rename.png]]<br />
<br />
{|style="background:#d9e5bf;font-size:100%; border:1px solid #aaa;" border="1" cellpadding="2" cellspacing="3" <br />
!style="background:#669900;color:#fff"| package.spec<br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"|<br />
|-<br />
| Name:<br />
| package<br />
|-<br />
| Version:<br />
| 1.1<br />
|-<br />
| Requires:<br />
|-<br />
| Provides:<br />
| pac = %version<br />
|-<br />
| Obsoletes:<br />
| pac < %version<br />
|-<br />
| Conflicts:<br />
|-<br />
|}<br />
<br />
Strictly speaking, giving the old package name in the <tt>Provides:</tt> field is only needed if another package requires the old package name. Please add the <tt>Version</tt> number to the field of the old package name, so a later re-renaming is possible. (For example: <tt>Provides: pac = 1.0</tt>). In 90% of the cases, you can just use <tt>%version</tt> as in the example above.<br />
<br />
However, the <tt>Provides:</tt> entry triggers the selection of the new package during update. It is this field which tells that it is taking over for the old package. The <tt>Obsoletes:</tt> just says to delete the package.<br />
The <tt>Version:</tt> field is irrelevant here, but you should also add the old package version number to the <tt>Obsoletes:</tt> field (in this example: <tt>Obsoletes: pac <= 1.0</tt>) to enable "the way back" to the old package name with a higher version number. As shown in the example, you can use <tt>%version</tt> here aswell. Be sure to only use "<" in that case, otherwise you can not revert to the old name within the same version.<br />
<br />
If you obsolete a subpackage with a different version number than the main package, you can not use <tt>%version</tt> in Provides/Obsoletes. Of course, you can use the same version string as in <tt>Version</tt> of the subpackage.<br />
<br />
Please also add a simple comment to the specfile, e. g. “<i># <tt>pac</tt> was last used in openSUSE 12.3</i>”. Without it, it will be hard to decide when it is possible to wipe these lines out. Otherwise, it may stay there forever.<br />
<br />
=== Replace a package by another with the same functionality ===<br />
<br />
[[Image:Rename.png]]<br />
<br />
{|style="background:#d9e5bf;font-size:100%; border:1px solid #aaa;" border="1" cellpadding="2" cellspacing="3"<br />
!style="background:#669900;color:#fff"| package.spec<br />
!style="background:#669900;color:#fff"|<br />
|-<br />
| Name:<br />
| package<br />
|-<br />
| Version:<br />
| 1.1<br />
|-<br />
| Requires:<br />
|-<br />
| Provides:<br />
| <br />
|-<br />
| Obsoletes:<br />
| pac < %version<br />
|-<br />
| Conflicts:<br />
|-<br />
|}<br />
<br />
Instead of ''renaming a package'', <tt>pac</tt> will be replaced by <tt>package</tt>, although <tt>package</tt> provides no files of <tt>pac</tt>. So <tt>package</tt> '''does not provide''' <tt>pac</tt>.<br />
<br />
This only works if one package obsoletes <tt>pac</tt> '''only'''. If there are more packages, the solver will not do this update.<br />
<br />
== Splitting and Merging ==<br />
<br />
=== Splitting off a sub-package ===<br />
<br />
[[Image:Split-a.png]]<br />
<br />
{|style="background:#d9e5bf;font-size:100%; border:1px solid #aaa;" border="1" cellpadding="2" cellspacing="3"<br />
!style="background:#669900;color:#fff"| pac.spec<br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"| pac-devel.spec<br />
!style="background:#669900;color:#fff"|<br />
|-<br />
| Name:<br />
| pac<br />
|<br />
| Name:<br />
| pac-devel<br />
|-<br />
| Version:<br />
| 1.1<br />
|<br />
| Version:<br />
| 1.1<br />
|-<br />
| Requires:<br />
|<br />
|<br />
| Requires:<br />
|-<br />
| Provides:<br />
|<br />
|<br />
| Provides:<br />
| pac:/file/from/pac<br />
|-<br />
| Obsoletes:<br />
|<br />
|<br />
| Obsoletes:<br />
|-<br />
| Conflicts:<br />
|<br />
|<br />
| Conflicts:<br />
|-<br />
|}<br />
<br />
=== Splitting a package into two ===<br />
<br />
[[Image:Split-b.png]]<br />
<br />
{|style="background:#d9e5bf;font-size:100%; border:1px solid #aaa;" border="1" cellpadding="2" cellspacing="3" <br />
!style="background:#669900;color:#fff"| firstpac.spec<br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"| secondpac.spec<br />
!style="background:#669900;color:#fff"|<br />
|-<br />
| Name:<br />
| firstpac<br />
|<br />
| Name:<br />
| secondpac<br />
|-<br />
| Version:<br />
| 1.1<br />
|<br />
| Version:<br />
| 1.1<br />
|-<br />
| Requires:<br />
|<br />
|<br />
| Requires:<br />
|-<br />
| Provides:<br />
| pac = 8.15<br />
|<br />
| Provides:<br />
| pac:/file/from/pac<br />
|-<br />
| Obsoletes:<br />
| pac <= 8.15<br />
|<br />
| Obsoletes:<br />
|-<br />
| Conflicts:<br />
|<br />
|<br />
| Conflicts:<br />
|-<br />
|}<br />
<br />
The example shown lists separate spec files for <tt>pac</tt> and<br />
<tt>pac-devel</tt>. (Remember that RPM allows to define sub-packages from a<br />
“main” package with a single <tt>.spec</tt> file.<br />
<br />
The dependency resolution (installing '''both''' new packages) is done by YaST with<br />
the ''split-alias'' mentioned in <tt>Provides:</tt> of <tt>pac-devel</tt>.<br />
<br />
It is up to the package maintainer to decide about dependencies between <tt>pac</TT><br />
and <TT>pac-devel</TT>.<br />
For example, if one wants to split a library package into a main, a <TT>-devel</TT>,<br />
and a <TT>-doc</TT> package, the main and the <tt>-doc</TT> package are independant, but<br />
the <tt>-devel</TT> package requires the main package.<br />
<br />
During an update, the aformentioned split-alias tag is important. YaST only<br />
updates already installed packages, in this case only the main package. Without the<br />
split-alias, this would remove files needed for development which<br />
were part of the old main package but are not in the new main package.<br />
<br />
The given <tt>Provides:</tt> for <tt>pac</TT> now triggers this update<br />
dependency as it tells YaST also to install <tt>pac-devel</TT> even though<br />
it was not installed before.<br />
<br />
{{Warning|Split-alias tags are used by YaST only, RPM never sees them.}}<br />
<br />
If a package is split in more than two packages, the split-alias<br />
tags must be mutually exclusive. It is the only way for YaST to correctly<br />
handle such update dependencies.<br />
<br />
''Important enhancement for the future''<br />
<br />
Splitting a library package into a main and a <TT>-devel</TT> package is always a good idea. But it does not make sense in every case&nbsp;— because sometimes, the <TT>-devel</TT> package would be too small or does not contain anything. In this case, just add a <TT>Provides: pac-devel = %version</TT> in the main package to do the trick that other packages can require this virtual <TT>-devel</TT> package.<br />
<br />
Please also add a simple comment to the specfile, e. g. “<i># <TT>-devel</TT> splitted in openSUSE 12.3</i>”. Without it, it will be hard to decide when it is possible to wipe these lines out. Otherwise it may stay there forever.<br />
<br />
=== Merging a package ===<br />
<br />
[[Image:Merge-a.png]]<br />
<br />
{|style="background:#d9e5bf;font-size:100%; border:1px solid #aaa;" border="1" cellpadding="2" cellspacing="3" <br />
!style="background:#669900;color:#fff"|package.spec <br />
!style="background:#669900;color:#fff"|<br />
|-<br />
|Name:<br />
|package<br />
|-<br />
|Version:<br />
|1.1<br />
|-<br />
|Requires:<br />
|-<br />
|Provides:<br />
|pac = 8.15<br />
|-<br />
|Obsoletes:<br />
|pac <= 8.15<br />
|-<br />
|Conflicts:<br />
|-<br />
|}<br />
This is comparable to a package rename. The new package must also incorporate<br />
the <tt>Provides</tt> and <tt>Obsoletes</tt> tags from the old package. This is<br />
needed to properly update from distribution before <TT>X</TT>.<br />
<br />
=== Merging two packages into a new one ===<br />
<br />
[[Image:Merge-b.png]]<br />
<br />
{|style="background:#d9e5bf;font-size:100%; border:1px solid #aaa;" border="1" cellpadding="2" cellspacing="3" <br />
!style="background:#669900;color:#fff"|package.spec<br />
!style="background:#669900;color:#fff"|<br />
|-<br />
| Name:<br />
| package<br />
|-<br />
| Version:<br />
| 1.1<br />
|-<br />
| Requires:<br />
|-<br />
| Provides:<br />
| pac1 = 8.15, pac2 = 2.3<br />
|-<br />
| Obsoletes:<br />
| pac1 <= 8.15, pac2 <= 2.3<br />
|-<br />
| Conflicts:<br />
|-<br />
|}<br />
<br />
== Handling alternatives ==<br />
<br />
=== Non conflicting ===<br />
<br />
[[Image:Non-conflicting.png]]<br />
<br />
{|style="background:#d9e5bf;font-size:100%; border:1px solid #aaa;" border="1" cellpadding="2" cellspacing="3" <br />
!style="background:#669900;color:#fff"| firstpac.spec<br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"| <br />
!style="background:#669900;color:#fff"| secondpac.spec<br />
!style="background:#669900;color:#fff"| <br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"| thirdpac.spec<br />
!style="background:#669900;color:#fff"|<br />
|-<br />
| Name:<br />
| firstpac<br />
|<br />
| Name:<br />
| secondpac<br />
|<br />
| Name:<br />
| thirdpac<br />
|-<br />
| Version:<br />
| 1.0<br />
|<br />
| Version:<br />
| 1.0<br />
|<br />
| Version:<br />
| 1.0<br />
|-<br />
| Requires:<br />
|<br />
|<br />
| Requires:<br />
|<br />
|<br />
| Requires:<br />
|-<br />
| Provides:<br />
| Pac = 1.0<br />
|<br />
| Provides:<br />
| Pac = 1.0<br />
|<br />
| Provides:<br />
| Pac 1.0<br />
|-<br />
| Obsoletes:<br />
|<br />
|<br />
| Obsoletes:<br />
|<br />
|<br />
| Obsoletes:<br />
|-<br />
| Conflicts:<br />
|<br />
|<br />
| Conflicts:<br />
|<br />
|<br />
| Conflicts:<br />
|-<br />
|}<br />
<br />
All three package provide the ''capability'' '''Pac''' and can be installed in parallel.<br />
<br />
(The upper case letter in Pac is choosen on purpose to distinguish this tag from a package. Such capabilities must be agreed upon within the openSUSE community. Ask on the "opensuse-packaging" mailing list before inventing your own tag!).<br />
<br />
Example: <tt>xdm</tt> and <tt>kdm</tt> provide capability "Display-Manager".<br />
<br />
=== Partially conflicting ===<br />
[[Image:Partly-conflicting.png]]<br />
<br />
{|style="background:#d9e5bf;font-size:100%; border:1px solid #aaa;" border="1" cellpadding="2" cellspacing="3"<br />
!style="background:#669900;color:#fff"| firstpac.spec<br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"| <br />
!style="background:#669900;color:#fff"| secondpac.spec<br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"| thirdpac.spec<br />
!style="background:#669900;color:#fff"|<br />
|-<br />
| Name:<br />
| firstpac<br />
|<br />
| Name:<br />
| secondpac<br />
|<br />
| Name:<br />
| thirdpac<br />
|-<br />
| Version:<br />
| 1.0<br />
|<br />
| Version:<br />
| 1.0<br />
|<br />
| Version:<br />
| 1.0<br />
|-<br />
| Requires:<br />
|<br />
|<br />
| Requires:<br />
|<br />
|<br />
| Requires:<br />
|-<br />
| Provides:<br />
| Pac = 1.0<br />
|<br />
| Provides:<br />
| Pac = 1.0<br />
|<br />
| Provides:<br />
| Pac = 1.0<br />
|-<br />
| Obsoletes:<br />
|<br />
|<br />
| Obsoletes:<br />
|<br />
|<br />
| Obsoletes:<br />
|-<br />
| Conflicts:<br />
| secondpac<br />
|<br />
| Conflicts:<br />
| firstpac<br />
|<br />
| Conflicts:<br />
|-<br />
|}<br />
<br />
The <tt>Conflicts</tt> express that only either firstpac '''or''' secondpac might be installed, but not both.<br />
<br />
=== Mutually exclusive ===<br />
[[Image:Mutually-exclusive.png]]<br />
<br />
{|style="background:#d9e5bf;font-size:100%; border:1px solid #aaa;" border="1" cellpadding="2" cellspacing="3" <br />
!style="background:#669900;color:#fff"| firstpac.spec<br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"| secondpac.spec<br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"|<br />
!style="background:#669900;color:#fff"| thirdpac.spec<br />
!style="background:#669900;color:#fff"|<br />
|-<br />
| Name:<br />
| firstpac<br />
|<br />
| Name:<br />
| secondpac<br />
|<br />
| Name:<br />
| thirdpac<br />
|-<br />
| Version:<br />
| 1.0<br />
|<br />
| Version:<br />
| 1.0<br />
|<br />
| Version:<br />
| 1.0<br />
|-<br />
| Requires:<br />
|<br />
|<br />
| Requires:<br />
|<br />
|<br />
| Requires:<br />
|-<br />
| Provides:<br />
| Pac = 1.0<br />
|<br />
| Provides:<br />
| Pac = 1.0<br />
|<br />
| Provides:<br />
| Pac = 1.0<br />
|-<br />
| Obsoletes:<br />
|<br />
|<br />
| Obsoletes:<br />
|<br />
|<br />
| Obsoletes:<br />
|-<br />
| Conflicts:<br />
| secondpac thirdpac<br />
|<br />
| Conflicts:<br />
| firstpac thirdpac<br />
|<br />
| Conflicts:<br />
| firstpac secondpac<br />
|-<br />
|}<br />
<br />
Only one of firstpac, secondpac, or thirdpac might be installed.<br />
<br />
[[de:openSUSE:Paketabhängigkeiten]]<br />
[[Category:Packaging documentation]]</div>Etorres4https://en.opensuse.org/index.php?title=openSUSE:Packaging_Go&diff=130728openSUSE:Packaging Go2018-12-10T22:10:29Z<p>Etorres4: Fix small misspelling</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 />
vendor: 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 />
== Not all packages will be accepted ==<br />
<br />
Not all packages will find their way into the devel:languages:go project.<br />
Packages that will be accepted include binary packages (e.g. clair or packer) and their direct and indirect dependencies.<br />
All other packages will most likely not be added.<br />
We recommend using `<tt>go get</tt>` for such packages.<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 />
= Example template =<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 />
%{go_nostrip}<br />
<br />
Name: golang-$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 />
%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 />
%gofilelist<br />
<br />
%check<br />
%gotest $IMPORTPATH_NAMESPACE<br />
<br />
%files -f file.lst<br />
%doc README LICENSE<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_nostrip ===<br />
<br />
It will disable stripping of the binary, this causes quite often issues related to tools written in Go.<br />
<br />
=== %go_requires ===<br />
<br />
'''Removed''' in golang-packaging v15.0.0.<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 />
'''Removed''' in golang-packaging v15.0.0.<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 />
'''Removed''' in golang-packaging v15.0.0.<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 />
=== %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 />
=== %gosrc ===<br />
<br />
It will scan the source directory and copy all *.go, *.s, and *.h files to ''%{go_contribsrcdir}''.<br />
<br />
=== %gofilelist ===<br />
<br />
It will scan ''%{go_contribsrcdir}'' for files and directories, and generate a file (file.lst) listing each.<br />
This file can then be used for the <code>%files</code> macro, see [[openSUSE:Packaging_Go#Example_template|here]].<br />
<br />
=== %godoc ===<br />
<br />
'''No-op''' in golang-packaging v15.0.0.<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 importpath===<br />
<br />
It will test all golang codes inside importpath 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 destroy 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 />
After running <code>%goprep</code>, an additional Go-specific directory structure is created.<br />
All files from ''BUILD/%{name}-%{version}'' are then be copied to the new directory ''BUILD/go/src/$IMPORTPATH''.<br />
<br />
Although RPM will still <code>cd</code> into ''BUILD/%{name}-%{version}'' when reaching the sections <code>%build</code> or <code>%install</code>, this new directory structure is necessary for the package itself and its dependencies.<br />
It will also be set in the ''GOPATH'' environment variable which in turn is used when running <code>%gobuild</code>.<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}<br />
<br />
=== Layout after %goinstall ===<br />
<br />
After running <code>%goinstall</code>, the package will be installed to<br />
<br />
BUILD/usr/bin/<br />
<br />
Static libraries (*.a files) are not installed, and therefore won't be part of the shipped package. <br />
<br />
=== Layout after %gosrc ===<br />
<br />
After running <code>%gosrc</code>, your package source will be installed into <br />
<br />
BUILDROOT/%{_datadir}/go/contrib/src/pkg/xxx/xxx/%{name}/<br />
<br />
It will copy *.go files, as well as *.s and *.h files. Should any other files be required, these have to be copied manually 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 has subdirectories, they will be compiled as xxx/xxx/%{name}/<subdirectory-name>.a or xxx/xxx/%{name}/<subdirectory-name>/<some-other-name>.a. But anyway:<br />
<br />
xxx/xxx/%{name}/*.go will be compiled 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 also 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), it will cause an error when the user runs the package:<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 />
This can be fixed by providing '''Requires''' and '''BuildRequires''':<br />
<br />
<pre><br />
Requires: golang(code.google.com/p/log4go)<br />
BuildRequires: golang(code.google.com/p/log4go)<br />
</pre><br />
<br />
Some errors however might seem a bit more complicated to solve:<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 />
In this case, simple tests on your local can help locating the problem:<br />
* For a library: You can just download the source from upstream and run <code>go run xxx.go</code> to see where it fails.<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 />
For such Golang wrappers it may therefore be necessary to install a ''*-devel'' package in order for the package to build.<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 />
== 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>Etorres4