Debian upstream

From Free Pascal wiki

On Debian distribution, the upstream source is the code of the program that can be compiled for any target platform. It needs to be compilable using packages already available in the latest Debian distribution.

If you want to distribute the .deb file directly, you may generate it following Debian package structure.

Dependence on Lazarus custom packages

Generally Debian packages will use dynamically linked libraries, that will be provided as another Debian package. However in Lazarus, it is common to use statically linked libraries that are provided as Lazarus custom packages (the main file have .lpk extension).

If you are using custom Lazarus packages, you will need to include them in the upstream source. You can do that by copying the custom packages source code into your projects repository or create an upstream repository that will contain your own project as well as all custom packages source code.

Publishing a new version of your project on Debian will thus require you to copy the source of used packages with the adequate version number. It is recommended to specify the required package version in the project inspector, so that you won't use an outdated custom package for compilation and also that you will be able to know which version is supposed to be used.

Upstream source, package maintainer and sponsor

There are different levels when it comes to uploading packages into Debian:

  • upstream source provided by the software developer
  • Debian package source provided by the package maintainer
  • upload done by the package sponsor/mentor

Note that it may be difficult to find a package maintainer so that the developer can as a matter of fact be the maintainer as well. This article talks only about the upstream source.

The term sponsor/mentor does not refer to a financial support but to a Debian developer.

Upstream source content

The upstream source consists of:

  • you project source code and custom Lazarus packages source code
  • compilation scripts
  • additional information about the program

It can be organized for example like this:

upstream
  ├─ myproject ...     # folder for main project (containing a .lpi file)
  ├─ custompackage ... # folder for custom package (containing a .lpk file)
  ├─ configure         # script to setup compilation
  ├─ Makefile          # compilation and installation script
  └─ info
      ├─ myproject.1         # command line manual
      ├─ myproject.desktop   # GUI application description
      └─ icons               # GUI icons
          ├─ 16x16.png
          ├─ 32x32.png
          ...

In all cases, the debian folder name is reserved for the Debian package so the upstream must not contain such folder unless it takes the responsibility of describing the Debian package.

Common icon sizes: 16x16, 22x22, 24x24, 32x32, 36x36, 48x48, 64x64, 256x256, scalable, symbolic. Scalable and symbolic are in SVG format. You don't need to provide all of them, they will be stretched if necessary.

Project and custom packages

It is recommended to use a specific folder for each custom package, though there is no restriction here. You just need to remember the path to those when writing the Makefile.

Command line manual

The syntax is of the .1 file is a bit peculiar. There are some tools to help but you still need to know the syntax.

Here is a sample file:

.TH Project1 1 "19 May 2020" "" Project1
.SH NAME
Project1 - My cool project
.SH SYNOPSIS
.B project1
[PARAMETER]
.SH DESCRIPTION
What my program does.
.PP
More description.

Application description

To add your application to the Linux menu, you need to add a file called *.desktop containing:

[Desktop Entry]
Name=Project1
Comment=Cool project
Icon=project1
Exec=project1
Terminal=false
Type=Application
Categories=Graphics
GenericName=Project1
Keywords=feature1; feature2; feature3

This file is similar to a shortcut to your program.

The Categories field is similar to the one in the control file. It can be for example: Communication, Database, Development, Editors, Electronics, Fonts, Games, Graphics, Math, Internet, Networking, News, Science, Sound, Utility, Video.

The keywords help search through applications.

configure script

The script called configure is a script that is called initially before compilation. It can be used to detect the compilation environment and take appropriate actions. In the case of Lazarus, the bare minimum is to handle the prefix parameter. Here is for example a simple script that will store the prefix parameter in a file called prefix.

#!/bin/bash
args=("$@")
defaultprefix=/usr/local
wantedprefix=$defaultprefix
for param in "${args[@]}"
do
	if [ "$param" == "-h" ] || [ "$param" == "--help" ]; then
		echo "Usage: ./configure [OPTIONS]"
		echo ""
		echo "    --prefix=PREFIX"
		echo "        Specifies the install prefix."
		echo "        By default prefix is \"$defaultprefix\"" 
		echo "        For packages use \"/usr\""
		exit 0
	elif [ "${param:0:9}" == "--prefix=" ]; then
		wantedprefix=${param:9}
	else
		echo "Warning: unknown option $param"
	fi
done
echo "Prefix set to: $wantedprefix"
echo $wantedprefix >prefix  # store the prefix into the file called "prefix"

Here are examples of calls:

./configure                 # when testing the program locally
./configure --prefix=/usr   # when building the package

Makefile

Initialization

The Makefile is a sort of script. It does not have a shebang (line starting with "#!") and uses by default the minimalist shell /bin/sh. You can override it though and use bash with something like:

SHELL := /bin/bash

Note that in the Makefile, unlike a regular script, to access a variable one write $(VARIABLE) with brackets instead of ${VARIABLE} with braces. To run a shell command and retrieve the result, the brackets will also be used, which can be a little bit confusing.

Variables are set using := operator. For example, to compute the actual target path, one can write the following:

prefix := $(shell cat prefix)   # retrieve the content of the file called "prefix"
TARGET_DIR = $(DESTDIR)$(prefix)

When building locally, DESTDIR will be empty so that the target path will be the same as prefix. When building the package though, DESTDIR will indicate a temporary folder to use.

To make things easier to update, let's define the name of your project (without the .lpi extension):

PROJECT_NAME := myproject
Compiling

After the initialization of variables, the Makefile consists of entries called rules. The syntax of a rule is the following:

rule1: require1 require2
#... how to make it

Here the name of the rule is rule1 and it requires the rules require1 and require2 to be already made. This means that first require1 and require2 will be made and only afterwards rule1 will be made. The following lines contain the instructions to execute to make rule1.

If a rule does not need any other, there won't be anything after the colon. In the case of a Lazarus project, one can simply write:

all:
	lazbuild --build-mode=Release $(PROJECT_NAME)/$(PROJECT_NAME).lpi

The rule all is the one invoked to compile the program. Note that before the instructions, a tab character is needed (not spaces). It is recommended to specify the build-mode, because there may be various build modes like Debug or for different widgetsets (gtk2, gtk3, qt4, qt5). So whatever build mode is active in the project, you will be assured of the build mode used to generate the Debian package.

To clean the compiled files, there is a need for another rule:

clean:
	rm -f $(PROJECT_NAME)/$(PROJECT_NAME)  # remove generated executable file
	rm -rf lib             # remove object files

Note that the object files may be in another folder. Check the project options.

For completeness, let's provide a rule to clean the whole building process:

distclean: clean clean_configure
clean_configure:
	rm -f prefix     # remove the "prefix" file generated by "configure" script
Installation and package building

The Makefile needs to be able to install files on the system or to put them in the package. Both will be done with the same code and when building a package, the target directory will instead be a temporary one.

We will need additional folders for the installation.

BIN_DIR = $(TARGET_DIR)/bin                  # executable file
SHARE_DIR = $(TARGET_DIR)/share              # other files
RESOURCE_DIR = $(SHARE_DIR)/$(PROJECT_NAME)  # custom resources
MANUAL_DIR = $(SHARE_DIR)/man                # man page
ICON_DIR = $(SHARE_DIR)/icons/hicolor        # icons (multiple resolutions)
PIXMAP_DIR = $(SHARE_DIR)/pixmaps            # pixmap (fallback icon)

SRC_BIN_DIR = $(PROJECT_NAME)
SRC_INFO_DIR = info
SRC_ICON_DIR = $(SRC_INFO_DIR)/icons

One can retrieve all icons in the folder with:

SRC_ICONS = $(shell find "$(SRC_ICON_DIR)" -maxdepth 1 -type f -name *x*.png -exec basename {} .png ';')
Installation rule

The installation will require the prefix file to exist. This can be specified like any other rule:

install: prefix
	install -D "$(SRC_BIN_DIR)/$(PROJECT_NAME)" "$(BIN_DIR)/$(PROJECT_NAME)"
	install -d "$(SHARE_DIR)/man/man1"
	gzip -9 -n -c "$(SRC_INFO_DIR)/man/man1/$(PROJECT_NAME).1" >"$(SHARE_DIR)/man/man1/$(PROJECT_NAME).1.gz"
	chmod 0644 "$(SHARE_DIR)/man/man1/$(PROJECT_NAME).1.gz"
	install -D "$(SRC_INFO_DIR)/$(PROJECT_NAME).desktop" "$(SHARE_DIR)/applications/$(PROJECT_NAME).desktop"
	install -D --mode=0644 "$(SRC_ICON_DIR)/48x48.png" "$(SHARE_DIR)/pixmaps/$(PROJECT_NAME).png"
	for s in $(SRC_ICONS); do install -D --mode=0644 "$(SRC_ICON_DIR)/$$s.png" "$(ICON_DIR)/$$s/apps/$(PROJECT_NAME).png"; done

Note:

  • copying is done using the install command. The -D option will create missing directories for the file and the -d option will create the specified directory. The option --mode=0644 must be used for data files.
  • the 48x48 icon is used as default pixmap.
  • there are no resources installed in this case but you can add them in a similar way using install command.
Uninstallation rule

A similar rule must be created to uninstall the software:

uninstall: prefix
	rm -f "$(BIN_DIR)/$(PROJECT_NAME)"
	rm -f "$(SHARE_DIR)/man/man1/$(PROJECT_NAME).1.gz"
	rm -f "$(SHARE_DIR)/applications/$(PROJECT_NAME).desktop"
	rm -f "$(SHARE_DIR)/pixmaps/$(PROJECT_NAME).png"
	for s in $(SRC_ICONS); do rm -f "$(ICON_DIR)/$$s/apps/$(PROJECT_NAME).png"; done

Compiling upstream

Once you have all upstream files ready, you can check it compiles by going into the upstream folder and doing:

./configure
make
sudo make install
#test the program
sudo make uninstall

Note that before installing, make sure your program is not already installed on the system. Otherwise you won't be able to check that the installation was successful.

To test that the command line is working, simply call your program or check the manual:

myproject
man myproject

To test that the GUI is working, go in the Linux menu and find your program. Check that it is displayed with the appropriate icon.

If everything works, the next step is to get your upstream packaged. You can request that someone take care of it by sending an RFP bug request: https://wiki.debian.org/RFP

If you don't get any answer, you may want to do the packaging yourself. See Debian package source.