Craft/Blueprints: Difference between revisions
(→Structure: Fill out the sample blueprint a bunch) |
|||
Line 14: | Line 14: | ||
== Structure == | == Structure == | ||
The following shows an example blueprint file. Outside of the information in the various fields which define the software package itself, and that there is one file missing (blocklist.txt, which you can see the description of in the comment above the line which references that file), this is what a blueprint looks like. Since there is no project named category/projectname.git on KDE's Invent, the blueprint won't just build, but apart from that, this is what they look like. | |||
<syntaxhighlight lang="python"> | <syntaxhighlight lang="python"> | ||
import info | import info | ||
class subinfo(info.infoclass): | class subinfo(info.infoclass): | ||
# | # This defines the basic information about your software package (both the basic | ||
# metainformation like human readable names, where the source comes from, and | |||
# what other blueprints it depends on). | |||
def setTargets(self): | |||
# The human-readable name of the main binary | |||
self.displayName = "Your Project" | |||
# A description of the entire package | |||
self.description = "A really solid software package that does nifty things" | |||
# The project's webpage (if you're unsure for a KDE project, just use this one) | |||
self.webpage = "https://kde.org" | |||
# You can set various targets. By convention, call your primary one "master" | |||
# and then give the git URL for the project. If you need to specify a branch, | |||
# you can do so by adding a pipe and the name of the branch (or indeed tag) | |||
# to the line | |||
self.svnTargets["master"] = "https://invent.kde.org/category/projectname.git|branch" | |||
# The default target is what Craft will use to build your package if it is not | |||
# told anything else (by either the command line, or another blueprint which | |||
# depends on yours). | |||
self.defaultTarget = "master" | |||
def setDependencies( self ): | def setDependencies( self ): | ||
# Defines the blueprints this blueprint depends on | # Defines the blueprints this blueprint depends on, and which target (default is what | ||
# was defined above, and is usually what you would write, except in highly specific | |||
# cases). These are the directories inside the blueprints directory which contain | |||
# the blueprint for the thing this blueprint depends on. | |||
# A buildDependencies entry is something required for actually building the | |||
# software in this blueprint | |||
self.buildDependencies["dev-utils/pkg-config"] = "default" | |||
# a runtimeDependencies entry is something which must also be installed for the | |||
# software to function (and which will also then be included in any package you | |||
# build using Craft) | |||
self.runtimeDependencies["libs/qt5/qtbase"] = "default" | |||
# If there are compiler specific things to consider, either a library you need | |||
# for a specific compiler and not for others, you can use CraftCore.compiler to | |||
# make such checks. | |||
if CraftCore.compiler.isMinGW(): | |||
self.runtimeDependencies["libs/runtime"] = None #mingw-based builds need this | |||
from Package.CMakePackageBase import * # The package base | from Package.CMakePackageBase import * # The package base | ||
class Package(CMakePackageBase): | class Package(CMakePackageBase): | ||
# | # This defines which build system your blueprint should use. In this case, we are | ||
def __init__(self): | # using the CMake package base, but there are a lot of options for specific use cases, | ||
# | # such as Meson, Perl, QMake, and Binary ones. See | ||
# https://invent.kde.org/packaging/craft/-/tree/master/bin/Package | |||
# for details on which package base options are available. For KDE projects, however | |||
# you will almost certainly be using CMake, and the others are commonly more useful | |||
# for when you are creating blueprints for new dependencies. | |||
def __init__( self ): | |||
# Always remember to just initialize the package base like so | |||
CMakePackageBase.__init__( self ) | |||
# If you have tests set up to build by default, for example, you might want to | |||
# disable those for Craft builds (usually, in KDE, those tests are more useful | |||
# for the CI system, and less useful for Craft, which is more useful for creating | |||
# installer packages and the like, not for automated testing purposes). You can | |||
# do this by setting the following option. | |||
CMakePackageBase.buildTests = False | |||
def createPackage(self): | |||
# Usually you will not need this entry, but in case your main executable is | |||
# called something else than the blueprint's name, you can set that here. | |||
# This allows Craft to pass this information to tools which build packages, | |||
# such as the one which builds appimages, which will then be able to work | |||
# on the correct executable. | |||
self.defines["appname"] = "mainexecutable" | |||
# For Windows, similarly to above, if your application is called something | |||
# other than your blueprint's name, you can explicitly pass in an icon from | |||
# somewhere on the Craft filesystem. Here we pick out an ico file from inside | |||
# the | |||
self.defines["icon"] = os.path.join(self.sourceDir(), "gemini", "calligragemini.ico") | |||
# For Windows, you can define a set of shortcuts by setting the shortcuts define with | |||
# multiple values, such as below: | |||
self.defines["shortcuts"] = [{"name" : self.subinfo.displayName, "target":"bin/mainexecutable.exe"}, | |||
{"name" : "The Other Application", "target" : "bin/differentexecutable.exe"}, | |||
{"name" : "A Bonus Tool", "target" : "bin/anotherexecutable.exe"}] | |||
# If you have files that get installed automatically, but which you know are | |||
# in fact not needed for the application to run (this will sometimes be the | |||
# case for example for building Windows packages, where you don't need some | |||
# of the things installed by some dependencies), you can list those files | |||
# in a list in some file, which is a list of regular expressions which will | |||
# be interpreted on a per-line basis, and any file which is matched by any line | |||
# will not be included in the package. | |||
self.blacklist_file.append(os.path.join(self.packageDir(), "blocklist.txt")) | |||
# Alternatively, you can add a direct filter on specific files by adding | |||
# lines like this one (which will cause Craft to not package any executable | |||
# file that is outside the two directories at the start, and is not named | |||
# one of the four names in the second paranthesis). | |||
self.addExecutableFilter(r"(bin|libexec)/(?!(mainexecutable|differentexecutable|anotherexecutable|update-mime-database)).*") | |||
# You can add packages that should be ignored for packaging purposes. This is | |||
# in many ways similar to adding a buildDependencies entry, but only ignores | |||
# this specific package (which can be handy if other things pull in a package | |||
# that your software doesn't need when publishing). | |||
self.ignoredPackages.append("dev-utils/sed") | |||
# In some cases, you need to do things depending on specific conditions, | |||
# such as building on anything that is not Linus, where you might wish to | |||
# not ship dbus. You can do this like so: | |||
if not CraftCore.compiler.isLinux: | |||
self.ignoredPackages.append("libs/dbus") | |||
# Finally, just call the packager itself to get the package actually created. | |||
return super().createPackage() | |||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Dependencies === | === Dependencies === | ||
The various things you can list as dependencies (and indeed reference in places which reference other blueprints) are the directory names in which you can find the python files which define other blueprints in this repository: https://invent.kde.org/packaging/craft-blueprints-kde/ | |||
=== Package Base === | === Package Base === |
Revision as of 11:21, 24 June 2021
Adding New Blueprints
Blueprints are stored in separate repositories. At the moment there are these repositories:
- [email protected]:packaging/craft-blueprints-kde.git (enabled by default)
To navigate to this repository on your local file system:
cs craft-blueprints-kde
If you want to add a new blueprint first of all you have to choose the right location (e.g. kde apps are located in the kde folder.
Structure
The following shows an example blueprint file. Outside of the information in the various fields which define the software package itself, and that there is one file missing (blocklist.txt, which you can see the description of in the comment above the line which references that file), this is what a blueprint looks like. Since there is no project named category/projectname.git on KDE's Invent, the blueprint won't just build, but apart from that, this is what they look like.
import info
class subinfo(info.infoclass):
# This defines the basic information about your software package (both the basic
# metainformation like human readable names, where the source comes from, and
# what other blueprints it depends on).
def setTargets(self):
# The human-readable name of the main binary
self.displayName = "Your Project"
# A description of the entire package
self.description = "A really solid software package that does nifty things"
# The project's webpage (if you're unsure for a KDE project, just use this one)
self.webpage = "https://kde.org"
# You can set various targets. By convention, call your primary one "master"
# and then give the git URL for the project. If you need to specify a branch,
# you can do so by adding a pipe and the name of the branch (or indeed tag)
# to the line
self.svnTargets["master"] = "https://invent.kde.org/category/projectname.git|branch"
# The default target is what Craft will use to build your package if it is not
# told anything else (by either the command line, or another blueprint which
# depends on yours).
self.defaultTarget = "master"
def setDependencies( self ):
# Defines the blueprints this blueprint depends on, and which target (default is what
# was defined above, and is usually what you would write, except in highly specific
# cases). These are the directories inside the blueprints directory which contain
# the blueprint for the thing this blueprint depends on.
# A buildDependencies entry is something required for actually building the
# software in this blueprint
self.buildDependencies["dev-utils/pkg-config"] = "default"
# a runtimeDependencies entry is something which must also be installed for the
# software to function (and which will also then be included in any package you
# build using Craft)
self.runtimeDependencies["libs/qt5/qtbase"] = "default"
# If there are compiler specific things to consider, either a library you need
# for a specific compiler and not for others, you can use CraftCore.compiler to
# make such checks.
if CraftCore.compiler.isMinGW():
self.runtimeDependencies["libs/runtime"] = None #mingw-based builds need this
from Package.CMakePackageBase import * # The package base
class Package(CMakePackageBase):
# This defines which build system your blueprint should use. In this case, we are
# using the CMake package base, but there are a lot of options for specific use cases,
# such as Meson, Perl, QMake, and Binary ones. See
# https://invent.kde.org/packaging/craft/-/tree/master/bin/Package
# for details on which package base options are available. For KDE projects, however
# you will almost certainly be using CMake, and the others are commonly more useful
# for when you are creating blueprints for new dependencies.
def __init__( self ):
# Always remember to just initialize the package base like so
CMakePackageBase.__init__( self )
# If you have tests set up to build by default, for example, you might want to
# disable those for Craft builds (usually, in KDE, those tests are more useful
# for the CI system, and less useful for Craft, which is more useful for creating
# installer packages and the like, not for automated testing purposes). You can
# do this by setting the following option.
CMakePackageBase.buildTests = False
def createPackage(self):
# Usually you will not need this entry, but in case your main executable is
# called something else than the blueprint's name, you can set that here.
# This allows Craft to pass this information to tools which build packages,
# such as the one which builds appimages, which will then be able to work
# on the correct executable.
self.defines["appname"] = "mainexecutable"
# For Windows, similarly to above, if your application is called something
# other than your blueprint's name, you can explicitly pass in an icon from
# somewhere on the Craft filesystem. Here we pick out an ico file from inside
# the
self.defines["icon"] = os.path.join(self.sourceDir(), "gemini", "calligragemini.ico")
# For Windows, you can define a set of shortcuts by setting the shortcuts define with
# multiple values, such as below:
self.defines["shortcuts"] = [{"name" : self.subinfo.displayName, "target":"bin/mainexecutable.exe"},
{"name" : "The Other Application", "target" : "bin/differentexecutable.exe"},
{"name" : "A Bonus Tool", "target" : "bin/anotherexecutable.exe"}]
# If you have files that get installed automatically, but which you know are
# in fact not needed for the application to run (this will sometimes be the
# case for example for building Windows packages, where you don't need some
# of the things installed by some dependencies), you can list those files
# in a list in some file, which is a list of regular expressions which will
# be interpreted on a per-line basis, and any file which is matched by any line
# will not be included in the package.
self.blacklist_file.append(os.path.join(self.packageDir(), "blocklist.txt"))
# Alternatively, you can add a direct filter on specific files by adding
# lines like this one (which will cause Craft to not package any executable
# file that is outside the two directories at the start, and is not named
# one of the four names in the second paranthesis).
self.addExecutableFilter(r"(bin|libexec)/(?!(mainexecutable|differentexecutable|anotherexecutable|update-mime-database)).*")
# You can add packages that should be ignored for packaging purposes. This is
# in many ways similar to adding a buildDependencies entry, but only ignores
# this specific package (which can be handy if other things pull in a package
# that your software doesn't need when publishing).
self.ignoredPackages.append("dev-utils/sed")
# In some cases, you need to do things depending on specific conditions,
# such as building on anything that is not Linus, where you might wish to
# not ship dbus. You can do this like so:
if not CraftCore.compiler.isLinux:
self.ignoredPackages.append("libs/dbus")
# Finally, just call the packager itself to get the package actually created.
return super().createPackage()
Dependencies
The various things you can list as dependencies (and indeed reference in places which reference other blueprints) are the directory names in which you can find the python files which define other blueprints in this repository: https://invent.kde.org/packaging/craft-blueprints-kde/
Package Base
See https://invent.kde.org/packaging/craft/-/tree/master/bin/Package for available package bases
Howto
Apply Patches
Apply a simple patch
# ...
def setTargets(self):
# ...
# "5.81.0" is the version the patch should be applied
self.patchToApply["5.81.0"] = [("patch-file.diff", 1)] # patch file, patch depth (= git apply -p<n> option)
self.patchLevel["5.81.0"] = 1
It is also possible to do fancy stuff like
# ...
def setTargets(self):
# ...
for ver in ["master"] + self.versionInfo.tarballs():
self.patchToApply[ver] = [("patch-file.diff", 1)]
self.patchLevel[ver] = 1
Check for Compiler/OS
If you want to run a command based on the current environment you can use CraftCore.compiler
if CraftCore.compiler.isWindows:
# do something only on windows
if not CraftCore.compiler.isGCC:
# don't do something with GCC
Take a look at https://invent.kde.org/packaging/craft/-/blob/master/bin/CraftCompiler.py to see all available options